次の例では、2 ポート advisor を実装する方法を示します。 このカスタム advisor のサンプルでは、サーバーのいずれか 1 つのポートで発生した障害を検出する機能を具体的に示しています。この検出は、そのポート自体の状況、および、同一サーバー・マシン上に あるもう 1 つのポート上で実行されている別のサーバー・デーモンの状況の両方に基づいて行われます。
例えば、ポート 80 上の HTTP デーモンが応答を停止した場合は、 ポート 443 上で実行されている SSL デーモンへのトラフィックのルーティング停止も 必要になることが考えられます。
このカスタム advisor は、標準 advisor よりもアグレッシブです。それは、応答を送信しないすべてのサーバーを機能が停止したサーバーであると見なし、ダウンの マークを付けるからです。標準 advisor では、応答のないサーバーは、処理速度の非常に遅いサーバーと 見なします。このカスタム advisor では、HTTP ポートか SSL ポートのいずれか一方から応答がないと、両方のポートがダウンしているというマークを サーバーに付けます。
このカスタム advisor を使用する際、管理者は、この advisor の 2 つのインスタンス、すなわち、HTTP ポート上のインスタンスと SSL ポート上のインスタンスを 開始します。この advisor では、HTTP 用と SSL 用の 2 つの静的なグローバル・ハッシュ・テーブルを インスタンス化します。各 advisor では、そのサーバー・デーモンとの通信を試行し、ハッシュ・テーブル内に このイベントの結果を保管します。各 advisor が基本 advisor クラスに戻す値は、各 advisor が自身のサーバー・デーモンと通信する機能と、 パートナー advisor が自身のデーモンと通信する機能との両方によって決まります。
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; //-------- // このカスタム advisor で使用するハッシュ・テーブルのテーブル・エレメントを定義します class ADV_nte implements Cloneable { private String sCluster; private int iPort; private String sServer; private int iLoad; private Date dTimestamp; //-------- // constructor public ADV_nte(String sClusterIn, int iPortIn, String sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // このエレメントは現在有効か、有効期限が切れているかを検査します。 public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // set lifetime as // 3 advisor cycles Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // value accessor(s) public int getLoadValue() { return iLoad; } //-------- // 複製 (スレッド間の破損を回避) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // カスタム advisor を定義します 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; //-------- // define tables to hold port-specific history information 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.0rnAccept: */*rnUser-Agent: " + "IBM_LB_Custom_Advisor\r\n\r\n"; //-------- // SSL client hello メッセージを使用してバイト配列を作成します public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // client hello (byte)0x03, (byte)0x00, // SSL バージョン (byte)0x00, (byte)0x03, // cipher spec len (バイト) (byte)0x00, (byte)0x00, // session ID len (バイト) (byte)0x00, (byte)0x10, // challenge data len (バイト) (byte)0x00, (byte)0x00, (byte)0x03, // cipher spec (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // challenge data (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 }; //-------- // constructor public ADV_twop() { super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT, ADV_TWOP_DEF_INTERVAL, "", false); // false = load balancer times the response setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // ハッシュ・テーブルに対する synchronized PUT および GET アクセス・ルーチン 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 の負荷を特定します int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // send request message // to server if (0 <= iRc) { // did the request return a failure? StringBuffer sbReceiveData = new StringBuffer("") // allocate a buffer // for the response iRc = caller.receive(sbReceiveData); // get response from server if (0 <= iRc) { // did the receive return a failure? if (0 < sbReceiveData.length()) { // データがあるか iLoad = SUCCESS; // 受信データを無視し、 // 成功コードを返します } } } return iLoad; } //-------- // getLoadSSL() - サーバーの応答に基づいて SSL の負荷を特定します 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); // Perform a receive. socket.getInputStream().read(); // 受信が成功した場合、 // 負荷 0 を返します。データの // 内容は関係なく、 // ADV_Thread スレッドが // 負荷を計算します。 iLoad = 0; } catch (IOException e) { // エラー時、iLoad はデフォルトでこれに設定されます。 } return iLoad; } //-------- // getLoad - HTTP メソッドと SSL メソッドの結果をマージします public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentClusterId(); // 現行クラスター・アドレス int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServerId(); String sHashKey = sCluster = ":" + sServer; // ハッシュ・テーブル・キー if (ADV_TWOP_PORT_HTTP == iPort) { // HTTP サーバーを処理します iLoadHTTP = getLoadHTTP(iConnectTime, caller); // HTTP の負荷を取得します ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // save HTTP load // information ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // get SSL // information if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // タイム・スタンプを確認します if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // is SSL // working? iLoad = iLoadHTTP; } else { // SSL が機能していないため、HTTP サーバーにダウンのマークを付けます iLoad= ADV_HOST_INACCESSIBLE; } } else { // SSL information is expired, so mark the // HTTP server down iLoad = ADV_HOST_INACCESSIBLE; } } else { // no load information about SSL, report // getLoadHTTP() results iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // SSL サーバーを処理します iLoadSSL = getLoadSSL(iConnectTime, caller); // SSL の負荷を取得します ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // SSL の負荷情報を保存します。 ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // get HTTP // information if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // check the timestamp if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // is HTTP // working? iLoad = iLoadSSL; } else { // HTTP サーバーが機能していないため、SSL にダウンのマークを付けます iLoad = ADV_HOST_INACCESSIBLE; } } else { // HTTP からの情報の有効期限が切れているため、SSL にダウンのマークを付けます iLoad = ADV_HOST_INACCESSIBLE; } } else { // no load information about HTTP, report // getLoadSSL() results iLoad = iLoadSSL; } } //-------- // エラー・ハンドラー else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }