En el ejemplo siguiente se muestra cómo implementar un asesor de dos puertos. En este ejemplo de asesor personalizado se muestra la capacidad de detectar anomalías de un puerto de un servidor basándose en su propio estado y en el estado de otro daemon del servidor que se ejecuta en otro puerto de la misma máquina servidor.
Por ejemplo, si el daemon HTTP del puerto 80 deja de responder, quizá prefiera también detener el tráfico de direccionamiento al daemon SSL en el puerto 443.
El asesor es más radical que los asesores estándar, porque considera cualquier servidor que no envía una respuesta que ha dejado de funcionar y lo marca como inactivo. Los asesores estándar consideran que los servidores que no responden son muy lentos. Este asesor marca un servidor como inactivo para los puertos HTTP y SSL basándose en la falta de respuesta por parte de cada puerto.
Para utilizar este asesor personalizado, el administrador inicia dos instancias del asesor: una en el puerto HTTP y otra en el puerto SSL. El asesor crea instancias de dos tablas hash globales estáticas, una para HTTP y otra para SSL. Cada asesor intenta comunicarse con el daemon de servidor y almacena los resultados de este suceso en la tabla hash. El valor que cada asesor devuelve a la clase de asesor base depende de la posibilidad de comunicarse con su propio daemon de servidor y la posibilidad del asesor asociado para comunicarse con el daemon.
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; //-------- // Definir el elemento de las tablas hash utilizadas en este asesor personalizado 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(); } //-------- // comprobar si este elemento es actual o caducado public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // establecer duración // como 3 ciclos de asesor 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; } //-------- // clonar (evita el daño entre hebras) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // definir el asesor personalizado 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; //-------- // definir tablas para contener información de historial específica de puerto 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"; //-------- // crear matriz de bytes con mensaje de saludo del cliente SSL public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // saludo del cliente (byte)0x03, (byte)0x00, // versión SSL (byte)0x00, (byte)0x03, // long. especif. cifrado (bytes) (byte)0x00, (byte)0x00, // long. ID sesión (bytes) (byte)0x00, (byte)0x10, // long. datos desafío (bytes) (byte)0x00, (byte)0x00, (byte)0x03, // especif. cifrado (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // datos de desafío (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 temporiza la respuesta setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // rutinas de acceso PUT y GET sincronizadas para las tablas hash 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 - determinar carga HTTP basada en la respuesta del servidor int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // enviar mensaje de solicitud // al servidor if (0 <= iRc) { // ¿la solicitud ha devuelto una anomalía? StringBuffer sbReceiveData = new StringBuffer("") // asignar un almacenamiento intermedio // para la respuesta iRc = caller.receive(sbReceiveData); // obtener respuesta del servidor if (0 <= iRc) { // ¿la recepción ha devuelto una anomalía? if (0 < sbReceiveData.length()) { // ¿hay datos ahí? iLoad = SUCCESS; // omitir los datos recuperados y // devolver código de resultado satisfactorio } } } return iLoad; } //-------- // getLoadSSL() - determinar carga SSL según la respuesta del servidor 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); // Realizar una recepción. socket.getInputStream().read(); // Si la recepción es satisfactoria, // se devuelve la carga 0. No nos // preocupa el contenido de los datos // y la carga se calcula con // la hebra ADV_Thread. iLoad = 0; } catch (IOException e) { // En caso de error, iLoad lo tomará como valor predeterminado. } return iLoad; } //-------- // getLoad - fusionar resultados de los métodos HTTP y SSL public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentClusterId(); // dirección actual de clúster int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServerId(); String sHashKey = sCluster = ":" + sServer; // clave de tabla hash if (ADV_TWOP_PORT_HTTP == iPort) { // manejar un servidor HTTP iLoadHTTP = getLoadHTTP(iConnectTime, caller); // obtener la carga para HTTP ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // guardar información // HTTP ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // obtener información // SSL if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // comprobar indicación horaria if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // ¿está funcionando // HTTP? iLoad = iLoadHTTP; } else { // SSL no funciona, marcar els servidor HTTP como inactivo iLoad= ADV_HOST_INACCESSIBLE; } } else { // la información de SSL ha caducado, marcar el // servidor HTTP como inactivo iLoad = ADV_HOST_INACCESSIBLE; } } else { // no hay información de carga sobre SSL, notificar // resultados de getLoadHTTP() iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // manejar un servidor SSL iLoadSSL = getLoadSSL(iConnectTime, caller); // obtener carga para SSL ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // guardar información de carga SSL ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // obtener información // HTTP if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // comprobar indicación horaria if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // ¿está funcionando // HTTP? iLoad = iLoadSSL; } else { // el servidor HTTP no funciona, marcar SSL como inactivo iLoad = ADV_HOST_INACCESSIBLE; } } else { // información caducada de HTTP, marcar SSL como inactivo iLoad = ADV_HOST_INACCESSIBLE; } } else { // no hay información de carga sobre HTTP, notificar // resultados de getLoadSSL() iLoad = iLoadSSL; } } //-------- // manejador de errores else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }