L'exemple suivant montre comment implémenter un conseiller à deux ports. Cet exemple de conseiller personnalisé illustre la possibilité de détecter l'échec d'un port d'un serveur en fonction de son propre statut et du statut d'un autre démon de serveur exécuté sur un autre port du même serveur.
Par exemple, si le démon HTTP sur le port 80 ne répond plus, vous pouvez arrêter également le routage du trafic vers le démon SSL sur le port 443.
Ce conseiller est plus agressif que les conseillers standard, car il prend en compte tout serveur qui n'envoie pas de réponse après s'être arrêté et le marque comme arrêté. Les conseillers standard, eux, considèrent que le serveur est lent. Ce conseiller marque un serveur comme étant arrêté pour les ports HTTP et SSL lorsque les ports ne répondent pas.
Pour utiliser ce conseiller personnalisé, l'administrateur démarre deux instances du conseiller : une pour le port HTTP et une autre pour le port SSL. Le conseiller instancie deux tables de hachage globales statiques, une pour HTTP et une autre pour SSL. Chaque conseiller tente de communiquer avec le démon du serveur et stocke les résultats de cet événement dans sa table de hachage. La valeur renvoyée par chaque conseiller à la classe du conseiller de base dépend de la possibilité de communiquer avec son propre démon serveur et de la faculté du conseiller partenaire de communiquer avec son démon.
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; //-------- // Définit l'élément table des tables de hachage utilisées dans le conseiller personnalisé class ADV_nte implements Cloneable { private String sCluster; private int iPort; private String sServer; private int iLoad; private Date dTimestamp; //-------- // constructeur public ADV_nte(String sClusterIn, int iPortIn, String sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // vérifie si l'élément est actuel ou s'il a expiré public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // définit la durée de vie qui // correspond à 3 cycle de conseiller Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // accesseur(s) à la valeur public int getLoadValue() { return iLoad; } //-------- // clone (évite l'altération entre les unités d'exécution) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // définit le conseiller personnalisé 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; //-------- // définit les tables qui doivent contenir les informations historiques du port 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"; //-------- // crée une matrice d'octets avec le message HELLO du client SSL public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // HELLO du client (byte)0x03, (byte)0x00, // version SSL (byte)0x00, (byte)0x03, // long. spéc. chiffrement (octets) (byte)0x00, (byte)0x00, // long. ID session (octets) (byte)0x00, (byte)0x10, // long. données réponse (octets) (byte)0x00, (byte)0x00, (byte)0x03, // spéc. chiffrement (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // données réponse (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 }; //-------- // constructeur 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; } //-------- // routines d'accès PUT et GET synchronisées pour les tables de hachage 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 : détermine la charge HTTP dans la réponse du serveur int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // envoie un message de demande // au serveur if (0 <= iRc) { // la demande a-t-elle retourné un échec ? StringBuffer sbReceiveData = new StringBuffer("") // alloue une mémoire tampon // à la réponse iRc = caller.receive(sbReceiveData); // obtient la réponse du serveur if (0 <= iRc) { // la réception a-t-elle renvoyé une erreur ? if (0 < sbReceiveData.length()) { // les données existent-elles ? iLoad = SUCCESS; // ignore les données extraites et // retourne le code de succès } } } return iLoad; } //-------- // getLoadSSL() : détermine la charge SSL en fonction de la réponse du serveur 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); // Exécute une réception. socket.getInputStream().read(); // Si la réception aboutit, // retourne la charge 0. Le contenu des // données n'a pas d'importance // et la charge est calculée par l'unité // d'xécution ADV_Thread. iLoad = 0; } catch (IOException e) { // En cas d'erreur, iLoad l'utilise par défaut. } return iLoad; } //-------- // getLoad - fusionne le résultat des méthodes HTTP et SSL public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentClusterId(); // adresse actuelle du cluster int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServerId(); String sHashKey = sCluster = ":" + sServer; // clé de table de hachage if (ADV_TWOP_PORT_HTTP == iPort) { // gère un serveur HTTP ¨iLoadHTTP = getLoadHTTP(iConnectTime, caller); // obtient la charge HTTP ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // enregistre les informations de charge // HTTP ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // obtient les informations // HTTP if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // vérifie l'horodatage if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // SSL // fonctionne-t-il ? iLoad = iLoadHTTP; } else { // SSL ne fonctionne pas ; le serveur HTTP est marqué comme étant arrêté iLoad= ADV_HOST_INACCESSIBLE; } } else { // les informations SSL ont expiré : le serveur HTTP // est marqué comme étant arrêté iLoad = ADV_HOST_INACCESSIBLE; } } else { // aucune information de charge sur SSL, signale // le résultat getLoadHTTP() iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // gère un serveur SSL iLoadSSL = getLoadSSL(iConnectTime, caller); // obtient la charge SSL ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // enregistre les infos SSL. ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // obtient les informations // HTTP if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // vérifie l'horodatage if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // HTTP // fonctionne-t-il ? iLoad = iLoadSSL; } else { // le serveur HTTP ne fonctionne pas ; le serveur SSL est marqué comme étant arrêté iLoad = ADV_HOST_INACCESSIBLE; } } else { // les informations HTTP ont expiré : SSL est marqué comme étant arrêté iLoad = ADV_HOST_INACCESSIBLE; } } else { // aucune information de charge sur HTTP, signale // le résultat getLoadSSL() iLoad = iLoadSSL; } } //-------- // gestionnaire des erreurs else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }