次の例では、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;
//--------
// Define the table element for the hash tables used in this custom 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();
}
//--------
// check whether this element is current or expired
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;
}
}
}
//--------
// define the custom 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.0¥r¥nAccept: */*¥r¥nUser-Agent: " +
"IBM_LB_Custom_Advisor\r\n\r\n";
//--------
// create byte array with SSL client hello message
public static final byte[] abClientHello = {
(byte)0x80, (byte)0x1c,
(byte)0x01, // client hello
(byte)0x03, (byte)0x00, // SSL version
(byte)0x00, (byte)0x03, // cipher spec len (bytes)
(byte)0x00, (byte)0x00, // session ID len (bytes)
(byte)0x00, (byte)0x10, // challenge data len (bytes)
(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 and GET access routines for the hash tables
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 - determine HTTP load based on server response
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()) { // is data there?
iLoad = SUCCESS; // ignore retrieved data and
// 成功コードを返します
}
}
}
return iLoad;
}
//--------
// getLoadSSL() - determine SSL load based on server response
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(); // If receive is successful,
// return load of 0. We are not
// concerned with data's contents,
// and the load is calculated by
// the ADV_Thread thread.
iLoad = 0;
} catch (IOException e) { // Upon error, iLoad will default to it.
}
return iLoad;
}
//--------
// getLoad - merge results from the HTTP and SSL methods
public int getLoad(int iConnectTime, ADV_Thread caller) {
int iLoadHTTP;
int iLoadSSL;
int iLoad;
int iRc;
String sCluster = caller.getCurrentClusterId(); // current cluster address
int iPort = getAdviseOnPort();
String sServer = caller.getCurrentServerId();
String sHashKey = sCluster = ":" + sServer; // hash table key
if (ADV_TWOP_PORT_HTTP == iPort) { // handle an HTTP server
iLoadHTTP = getLoadHTTP(iConnectTime, caller); // get the load for 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)) { // check the time stamp
if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // is SSL
// working?
iLoad = iLoadHTTP;
} else { // SSL is not working, so mark the HTTP server down
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) { // handle an SSL server
iLoadSSL = getLoadSSL(iConnectTime, caller); // get load for SSL
ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL);
putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // save SSL load info.
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 server is not working, so mark SSL down
iLoad = ADV_HOST_INACCESSIBLE;
}
} else { // expired information from HTTP, so mark SSL down
iLoad = ADV_HOST_INACCESSIBLE;
}
} else { // no load information about HTTP, report
// getLoadSSL() results
iLoad = iLoadSSL;
}
}
//--------
// error handler
else {
iLoad = ADV_HOST_INACCESSIBLE;
}
return iLoad;
}
}