Das folgende Beispiel zeigt, wie eine Advisor-Funktion mit zwei Ports implementiert wird. Dieses Beispiel für eine angepasste Advisor-Funktion veranschaulicht, wie Fehler für einen Port eines Servers basierend auf dem eigenen Status und dem Status eines anderen Serverdämons, der an einem anderen Port auf derselben Servermaschine ausgeführt wird, erkannt werden können.
Wenn der HTTP-Dämon an Port 80 beispielsweise nicht mehr reagiert, möchten Sie möglicherweise auch keinen Datenverkehr mehr an den SSL-Dämon an Port 443 weiterleiten.
Dieser Advisor ist aggressiver als Standard-Advisor, weil er jeden Server, der keine Antwort sendet, als funktionsunfähig betrachtet und deshalb als inaktiv markiert. Standard-Advisor-Funktionen stufen nicht reagierende Server als sehr langsam ein. Diese Advisor-Funktion markiert einen Server für den HTTP-Port und den SSL-Port als inaktiv, wenn einer der Ports keine Antwort liefert.
Zur Verwendung dieser angepassten Advisor-Funktion startet der Administrator zwei Instanzen des Advisors: eine für den HTTP-Port und eine für den SSL-Port. Die Advisor-Funktion instanziert zwei statische globale Hash-Tabellen, eine für HTTP und eine für SSL. Jede Advisor-Funktion versucht, mit ihrem Serverdämon zu kommunizieren, und speichert die Ergebnisse dieses Ereignisses in seiner Hash-Tabelle. Der Wert, den jede Advisor-Funktion an die Basis-Advisor-Klasse zurückgibt, hängt von der Fähigkeit der Advisor-Funktion zur Kommunikation mit seinem eigenen Serverdämon und der Fähigkeit der Partner-Advisor-Funktion zur Kommunikation mit deren Dämon ab.
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.manager.*; import com.ibm.internet.lb.server.SRV_ConfigServer; //-------- // Tabellenelement für die in dieser angepassten Advisor-Funktion verwendeten Hash-Tabellen definieren class ADV_nte implements Cloneable { private String sCluster; private int iPort; private String sServer; private int iLoad; private Date dTimestamp; //-------- // Konstruktor public ADV_nte(String sClusterIn, int iPortIn, String sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // Prüfen, ob dieses Element aktuell oder verfallen ist public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // 3 Advisor-Zyklen als // Lebensdauer festlegen Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // Zugriffsmechanismen für Werte public int getLoadValue() { return iLoad; } //-------- // Klonen (Beschädigung zwischen Threads vermeiden) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // Angepasste Advisor-Funktion definieren public class ADV_twop extends ADV_Base implements ADV_MethodInterface, ADV_AdvisorVersionInterface { static final int ADV_TWOP_PORT_HTTP = 80; static final int ADV_TWOP_PORT_SSL = 443; //-------- // Tabellen für portspezifische Protokollinformationen definieren static HashTable htTwopHTTP = new Hashtable(); static HashTable htTwopSSL = new Hashtable(); static final String ADV_TWOP_NAME = "twop"; static final int ADV_TWOP_DEF_ADV_ON_PORT = 80; static final int ADV_TWOP_DEF_INTERVAL = 7; static final String ADV_HTTP_REQUEST_STRING = "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + "IBM_LB_Custom_Advisor\r\n\r\n"; //-------- // Bytefeldgruppe mit einer Hello-Nachricht des SSL-Clients erstellen public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // Client-Hello (byte)0x03, (byte)0x00, // SSL-Version (byte)0x00, (byte)0x03, // Länge der Verschlüsselungsspezifikation (Bytes) (byte)0x00, (byte)0x00, // Länge der Sitzungs-ID (Bytes) (byte)0x00, (byte)0x10, // Länge der Anforderungsdaten (Bytes) (byte)0x00, (byte)0x00, (byte)0x03, // Verschlüsselungsspezifikation (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // Anforderungsdaten (byte)0xFD, (byte)0x3A, (byte)0x3C, (byte)0x18, (byte)0xAB, (byte)0x67, (byte)0xB0, (byte)0x52, (byte)0xB1, (byte)0x1D, (byte)0x55, (byte)0x44, (byte)0x0D, (byte)0x0A }; //-------- // Konstruktor public ADV_twop() { super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT, ADV_TWOP_DEF_INTERVAL, "", false); // false = Load Balancer regelt die Antwort setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // Synchronisierte PUT- und GET-Zugriffsroutinen für die Hash-Tabellen synchronized ADV_nte getNte(Hashtable ht, String sName, String sHashKey) { ADV_nte nte = (ADV_nte)(ht.get(sHashKey)); if (null != nte) { nte = (ADV_nte)nte.clone(); } return nte; } synchronized void putNte(Hashtable ht, String sName, String sHashKey, ADV_nte nte) { ht.put(sHashKey,nte); return; } //-------- // getLoadHTTP - HTTP-Last auf der Basis der Serverantwort bestimmen int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // Anforderungsnachricht an // den Server senden if (0 <= iRc) { // Hat die Anforderung einen Fehler zurückgegeben? StringBuffer sbReceiveData = new StringBuffer("") // Puffer für die Antwort // zuordnen iRc = caller.receive(sbReceiveData); // Antwort vom Server abrufen if (0 <= iRc) { // Hat receive einen Fehler zurückgegeben? if (0 < sbReceiveData.length()) { // Sind Daten vorhanden? iLoad = SUCCESS; // Abgerufene Daten ignorieren und // Erfolgscode zurückgeben } } } return iLoad; } //-------- // getLoadSSL() - SSL-Last auf der Basis der Serverantwort bestimmen int getLoadSSL(int iConnectTime, ASV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc; CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper( abClientHello); Socket socket = caller.getSocket(); try { socket.getOutputStream().write(abClientHello); // receive (Empfang) durchführen. socket.getInputStream().read(); // Bei erfolgreichem Empfang // 0 als Lastwert zurückgeben. Der // Dateninhalt spielt keine Rolle, // und die Last wird vom // ADV_Thread-Thread berechnet. iLoad = 0; } catch (IOException e) { // Bei einem Fehler als Standardwert für iLoad verwenden. } return iLoad; } //-------- // getLoad - Ergebnisse der HTTP- und SSL-Methoden zusammenführen public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentClusterId(); // aktuelle Clusteradresse int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServerId(); String sHashKey = sCluster = ":" + sServer; // Schlüssel für Hash-Tabelle if (ADV_TWOP_PORT_HTTP == iPort) { // HTTP-Server bearbeiten iLoadHTTP = getLoadHTTP(iConnectTime, caller); // Last für HTTP abrufen ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // HTTP-Lastinformationen // speichern ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // SSL-Informationen // abrufen if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // Zeitmarke prüfen if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // Funktioniert // SSL? iLoad = iLoadHTTP; } else { // SSL funktioniert nicht, deshalb HTTP-Server als inaktiv markieren iLoad= ADV_HOST_INACCESSIBLE; } } else { // SSL-Informationen sind verfallen, deshalb // HTTP-Server als inaktiv markieren iLoad = ADV_HOST_INACCESSIBLE; } } else { // Keine Lastinformationen zu SSL, // Ergebnisse von getLoadHTTP() melden iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // SSL-Server bearbeiten iLoadSSL = getLoadSSL(iConnectTime, caller); // Last für SSL abrufen ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // SSL-Lastinformationen speichern ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // HTTP-Informationen // abrufen if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // Zeitmarke prüfen if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // Funktioniert // HTTP? iLoad = iLoadSSL; } else { // HTTP-Server funktioniert nicht, dedshalb SSL als inaktiv markieren iLoad = ADV_HOST_INACCESSIBLE; } } else { // Verfallene Informationen von HTTP, deshalb SSL als inaktiv markieren iLoad = ADV_HOST_INACCESSIBLE; } } else { // Keine Lastinformationen für HTTP, // Ergebnisse von getLoadSSL() melden iLoad = iLoadSSL; } } //-------- // Fehlerbehandlungsroutine else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }