Usamos la versión Java 3.4.6 en este ejemplo. El ejemplo es conveniente para que todos discutan si no entienden después de aprenderlo.
La vinculación Java Zookeeper para desarrollar aplicaciones se compone principalmente de dos paquetes Java:
org.apache.zookeeper
org.apache.zookeeper.data
El paquete org.apache.zookeeper consiste en la definición de interfaz monitorizada por Zookeeper y varios manejadores de devolución de llamada para Zookeeper. Define las clases principales de la biblioteca de clases de cliente Zookeeper, así como definiciones estáticas de muchos tipos y estados de eventos Zookeeper. El paquete org.apache.zookeeper.data define características relacionadas con registros de datos (también conocidos como Znodes), como listas de control de acceso (ACL), IDS, estadísticas, etc.
Org.apache.zookeepers.server, org.apache.zookeepers.server.quorum y org.apache.zookeepers.server.upgrade Los paquetes en la API Java Zookeeper son parte de la implementación del servidor. El paquete org.apache.zookeeper.client se utiliza para consultar el estado del servidor Zookeeper.
Prepárese para el entorno de desarrollo
Apache Zookeeper es un software complejo, por lo que requiere ejecutar muchas otras bibliotecas de clase. La biblioteca de dependencia se incluye en el directorio LIB como un archivo JAR en la distribución Zookeeper. El nombre del archivo Core Zookeeper JAR es ZOOKEEPER-3.4.6.JAR, ubicado en el directorio de inicio.
Para desarrollar una aplicación Java Zlookeeper, debemos establecer el ClassPath en el jarlo Zookeeper, y todas las bibliotecas de terceros de las que depende Zookeeper. Hay un archivo zkenv.sh en el directorio bin, que se puede usar para establecer classpath.
Necesitamos establecer el script de la siguiente manera y ejecutar la siguiente declaración en la línea de comando:
$ Zoobindir = $ {zk_home}/bin $ fuente $ {zoobindir} /zkenv.shLa variable Shell Zk_Home se establece en la ruta para instalar Zookeeper, en mi configuración es/usr/share/Zookeeper. Después de eso, la variable classpath se establece correctamente, en mi sistema como este:
$ echo $ classpath /usr/share/zookeeper-3.4.6/bin/../build/classes: /usr/share/zookeeper-3.4.6/bin /../ build/lib/*. jar: /usr/shookeeper-3.4.6/bin /../ lib/slf4j-log4j12-1.6.1.1.1.1.1.Jar : /usr/share/zookeeper-3.4.6/bin /../ lib/slf4j-api-1.6.1.jar: /usr/share/zookeeper-3.4.6/bin /../ lib/netty-3.7.0.final.jar: /usr. : /usr/share/zookeeper-3.4.6/bin /../ lib/jline-0.9.94.jar: /usr/share/zookeeper-3.4.6/bin /../ Zookeeper-3.4.6.jar: /usr/share/zookeeeper-3.4.6/bin /../ src/java/jarb/*. : /usr/share/zookeeper-3.4.6/bin /../ conf:
En el sistema operativo de Windows, debe ejecutar el script Zkenv.cmd. Ahora puede usar la variable ClassPath para compilar y ejecutar programas Java escritos utilizando la API ZOOKEEPER. El script Zkenv.sh se puede encontrar en el archivo .bashrc del directorio de inicio en uni/linux para evitar usarlo cada vez que se inicia la sesión de shell.
El segundo primer programa Zookeeper
Para introducir la API Java Zookeeper, comencemos con un programa muy simple que puede conectarse a la instancia de Zookeeper en localhost y si la conexión es exitosa, imprimirá una lista de Znodes bajo la ruta raíz del espacio de nombres de Zookeeper.
El código para este programa es el siguiente:
/*Nuestro primer programa de Zookeeper*/import java.io.ioException; import java.util.arrayList; import java.util.list; import org.apache.zookeepers.keepeexception; import org.apache.zookeeper.zookeePer; public class Holazokeeperer = "localhost: 2181"; string zpath = "/"; list <string> zoochildren = new ArrayList <String> (); ZOOKEEPER ZK = new Zookeeper (hostport, 2000, null); if (Zk! = NULL) {try {zoOoChildren = '/': "); for (String Child: ZoChildren) {// imprime el childrensystem.out.println (child);}} capt (KeepeException e) {E.PrintStActAtRace ();} Catch (interruptedException e) {E.PrintStackTrace ();}}}Antes de construir y ejecutar el fragmento de código anterior, veamos qué hace específicamente. El código comienza con la declaración de importación. Usando estas declaraciones, importamos los paquetes requeridos por cada componente del programa. Como se mencionó anteriormente, el paquete org.apache.zookeeper contiene todas las clases e interfaces requeridas por el cliente para interactuar con el servidor Zookeeper. Después de importar el paquete, se define una clase llamada Hellozookeeper. Dado que nos conectamos a la instancia de Zookeeper que se ejecuta en el mismo sistema, defina las cadenas de host y puerto como Hosthost: 2181 en el método principal. La línea de código ZK = New Zookeeper (HostPort, 2000, NULL) llama al constructor Zookeeper, que intenta conectarse al servidor Zookeeper y devuelve una referencia. Para los programas de clientes que se conectan a la instancia del servidor Zookeeper y mantienen esa conexión, se requiere una sesión en tiempo real. En este ejemplo, la referencia devuelta por el objeto ZK instanciado por el constructor representa la sesión. La API Zookeeper se basa en esta referencia, y cada llamada de método requiere una referencia para ejecutar.
El constructor de la clase ZOOKEEPER utiliza el siguiente código para crear una referencia a la instancia de Zookeeper:
ZOOKEEPER (String ConnectString, Int SessionTimeOut, Watcher Watcher)
Los parámetros utilizados son los siguientes:
ConnectString: Host separado por comas: una lista de números de puerto, cada uno correspondiente a un servidor Zookeeper. Por ejemplo, 10.0.0.1:2001, 10.0.0.2:2002 y 10.0.0.3:2003 Representación del host válido: pares de coincidencia de puertos para conjuntos de Zookeeper de tres nodos. SessionTimeOut: Este es el tiempo de espera de la sesión en milisegundos. Este es el momento en que Zookeeper no recibió un latido del cliente antes de anunciar el final de la sesión. Observador: un objeto de observador que se notifica si se crea cuando ocurren los cambios de estado y los eventos de nodo. Este objeto del observador debe crearse por separado a través de una clase definida por el usuario, que implementa la interfaz del observador y pasa el objeto instanciado al constructor Zookeeper. Las aplicaciones de los clientes pueden recibir notificaciones de varios tipos de eventos, como conexiones faltantes, vencimiento de sesiones, etc.
La API Java Zookeeper define un constructor adicional con tres parámetros para especificar operaciones más avanzadas. El código es el siguiente:
Zookeeper (String ConnectString, intsiontimeout, Watcher Watcher, Boolean CanBeroadonly)
En el constructor anterior de la clase ZOOKEEPER, si se establece en True, el parámetro Boolean CanBeroadonly permite al cliente creado ingresar al modo de solo lectura en el caso de la partición de red. El modo de solo lectura es un escenario en el que el cliente no puede encontrar ninguna mayoría de los servidores, pero hay un servidor de partición accesible para conectarse a él en modo de solo lectura, que permite las solicitudes de lectura al servidor, mientras que las solicitudes de escritura no están permitidas. El cliente continúa tratando de conectarse a la mayoría de los servidores en segundo plano y al mismo tiempo permanece de solo lectura. Un servidor de partición es solo un subconjunto del grupo Zookeeper, que se forma debido a la asignación de red en el clúster. La mayoría de los servidores componen la mayoría de los quórsos en el conjunto.
El siguiente constructor muestra la definición de dos parámetros adicionales:
ZOOKEEPER (String ConnectString, Int SessionTimeOut, Watcher Watcher, Long SessionID, Byte [] SessionPasswd)
Este constructor permite que el objeto del cliente ZOOKEEper cree dos parámetros adicionales:
SessionId: en el caso en que el cliente se vuelva a conectar al servidor Zookeeper, se puede usar una ID de sesión específica para consultar la sesión de sesión conectada previamente: si la sesión especificada requiere una contraseña, puede especificar aquí
El siguiente constructor es una combinación de las dos primeras llamadas:
ZOOKEEPER (String ConnectString, Int Sessiontimeout, Watcher Watcher, Long SessionID, Byte [] SessionPasswd, Boolean CanBeroadonly)
Este constructor es una combinación de las dos primeras llamadas, lo que permite la reconexión a la sesión especificada con modo de solo lectura habilitada.
Nota
La documentación detallada de la API de Java para la clase Zookeeper se puede consultar en http://zookeeper.apache.org/doc/r3.4.6/api/index.html.
Ahora, de vuelta a nuestro programa Zookeeper. Después de llamar al constructor, si la conexión es exitosa, obtendremos una referencia al servidor Zookeeper. Pasamos la referencia al método GetChildren a través del siguiente código:
zoochildren = zk.getchildren (zpath, falso)
El método getChildren (ruta de cadena, reloj booleano) de la clase Zookeeper devuelve la lista de niños de Znode en la ruta dada. Simplemente iteramos sobre la lista devuelta por este método e imprimimos la cadena en la consola.
Nombra el programa Hellozookeeper.java y compile nuestro programa de la siguiente manera:
$ javac -cp $ classpath hellozookeeper.java
Antes de ejecutar el programa, necesitamos iniciar la instancia del servidor ZOOKEEPER usando el siguiente comando:
$ $ {Zk_home} /bin/zkserver.sh inicioEjecute el programa de la siguiente manera:
$ java -cp $ classpath hellozookeeper
El ejecutor imprimirá un mensaje de registro en la consola, mostrando la versión Zookeeper, la versión Java, Java ClassPath, la arquitectura del servidor, etc. Utilizado. Estos son algunos de estos mensajes de registro:
Los mensajes de registro generados por la API Java Zookeeper son muy útiles para la depuración. Nos proporciona información sobre el cliente que se conecta al servidor Zookeeper, estableciendo una sesión y otros antecedentes. Los últimos tres mensajes de registro que se muestran arriba nos dicen cómo el cliente inicia la conexión utilizando los parámetros especificados en el programa y cómo el servidor asigna la ID de sesión al cliente después de una conexión exitosa.
Finalmente, la ejecución del programa finalmente genera lo siguiente en la consola:
Podemos usar el shell Zookeeper para verificar la corrección del programa:
$ $ Zk_home/bin/zkcli.sh -server localhost
¡Felicidades! Acabamos de escribir con éxito nuestro primer programa de clientes Zookeeper.
En segundo lugar, implementa la interfaz del observador
El monitoreo del observador Zookeeper permite a los clientes recibir notificaciones de los servidores Zookeeper y manejar estos eventos cuando ocurren. La API Java Zookeeper proporciona una interfaz pública llamada Watcher que la clase de controlador de eventos del cliente debe implementar para recibir notificaciones de eventos sobre eventos del servidor Zookeeper. Programáticamente, las aplicaciones que usan dichos clientes manejan estos eventos registrando objetos de devolución de llamada con el cliente.
Implementaremos la interfaz del observador para manejar los eventos generados por ZOOKEEPER cuando se cambien los datos asociados con ZNODE.
La interfaz del observador se declara de la siguiente manera en el paquete org.apache.zookeeper:
Public Interface Watcher {Proceso void (evento WatchedEvent);}Para demostrar el monitor de datos Znode (observador), hay dos clases de Java: DataWatcher y DataUpdater. El DataWatcher se ejecutará todo el tiempo y escuchará los eventos NodedAtAchange desde el servidor Zookeeper en la ruta /myConfig especificada Znode. La clase DataUpdater actualizará periódicamente los campos de datos en esta ruta Znode, que generará eventos, y al recibir estos eventos, la clase DataWatcher imprimirá los datos cambiados en la consola.
El siguiente es el código de la clase DataWatcher.java:
import java.io.ioException; import org.apache.zookeeper.createMode; import org.apache.zookeeper.ekeException; import org.apache.zookeepers.watchedEvent; importar org.apache.zookeeper.watcher; import org.apache.zookeeper.zogeDefs; importar; import org.apache.zookeepers.zookeeper; public class DataWatcher implementa Watcher, runnable {private static string hostPort = "localhost: 2181"; private static string zoodatapath = "/myconfig"; byte zoo_data [] = null; zookeeper zk; public datawatcher () {try {ZK = new Zkper, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000. esto); if (zk! = null) {try {// crea el znode si no existe, con el siguiente código: if (zk.exists (zoodatapath, this) == null) {zk.create (zoodatapath, ".getByTes (), zoodefs.ids.open_acl_unsafe, createMode.persistent);} (} (} (} (} (} (}); InterruptedException e) {E.PrintStackTrace ();}}} Catch (ioException e) {E.PrintStackTrace ();}} public void printData () lanza interruptedException, KeepeException {zoo_data = Zk.getData (ZOODAPATH, this, null); String Zstring = new String (neoo (neoo (neoo); El contenido actual del zNode a la consola: system.out.printf ("/ncurrent data @ zk ruta %s: %s", zoodatapath, zString);} @ overridePublic void Process (WatchedEvent Event) {System.out.printf ("/NEVENT recibido: %S", Event.ToString ()); // We Will Process Solution Of Type of type of type de type de type de type. (event.getType () == Event.eventType.nodedAtACHANGED) {try {printData ();} capt (interruptedException e) {e.printstackTrace ();} catch (keepeXception e) {e.printstackTraCe {DataWatcher DataWatcher = new DataWatcher (); DataWatcher.PrintData (); DataWatcher.run ();} public void run () {try {sincronizado (this) {while (true) {Wait ();}}} Catch (InterrumeStEdException e) {E.PrintStackTrace (); Thread.CurrentThread (). Interrupt ();}}}Echemos un vistazo al código de la clase DataWatcher.java para comprender la implementación de un monitor Zookeeper. La clase pública DataWatcher implementa la interfaz del observador y la interfaz ejecutable, y tiene la intención de ejecutar el monitor como un hilo. El método principal crea una instancia de la clase DataWatcher. En el código anterior, el Constructor DataWatcher intenta conectarse a una instancia de Zookeeper que se ejecuta en LocalHost. Si la conexión es exitosa, usamos el siguiente código para verificar si existe la ruta Znode/MyConfig:
if (zk.exists (Zoodatapath, esto) == nulo) {Si el ZNode no existe en el espacio de nombres de Zookeeper, la llamada del método Exists devuelve NULL e intente crearlo como un ZNode persistente usando el código de la siguiente manera:
zk.create (Zoodatapath, "" .getBytes (), Zoodefs.ids.open_acl_unsafe, createMode.Persistent);
El siguiente es el método de proceso, que se declara en la interfaz del observador de org.apache.zookeeper e implementado por la clase DataWatcher utilizando el siguiente código:
Proceso de vacío público (evento WatchedEvent) {Para simplificar, en el método de proceso, los eventos recibidos de la instancia de Zookeeper se imprimen y solo los eventos de tipo nodochanged se procesan más de la siguiente manera:
if (event.gettype () == event.eventType.nodedAtAchanged)
Cuando se produce cualquier actualización o cambio en el campo de datos de la ruta Znode/MyConfig y se recibe un evento de tipo NodeDACHANGED, se llama al método PrintData para imprimir el contenido actual del ZNODE. Al ejecutar una llamada GetData en ZNode, establecemos un monitor nuevamente, que es el segundo parámetro del método, como se muestra en el siguiente código:
zoo_data = zk.getData (Zoodatapath, this, null);
Los eventos de monitoreo son desencadenantes únicos enviados a clientes que establecen monitoreo. Para recibir continuamente más notificaciones de eventos, los clientes deben restablecer el monitor.
DataUpdater.java es una clase simple que se conecta a la instancia de Zookeeper que ejecuta el LocalHost y actualiza el campo de datos de la ruta Znode/MyConfig con una cadena aleatoria. Aquí elegimos actualizar el ZNode con una cadena de identificador único universal (UUID), porque las llamadas de generador UUID posteriores garantizarán la generación de cadenas únicas.
El código de clase DataUpdater.java es el siguiente:
import java.io.ioException; import java.util.uuid; import org.apache.zookeeper.ekeePeexception; import og.apache.zookeeperer.watchedevent; import org.apache.zookeePer.watcher; import org.apache.zookeePer.zookeeper; "localhost: 2181"; private static string zoodatapath = "/myconfig"; Zookeeper Zk; public dataUpDater () lanza ioexception {try {zk = new Zookeeper (hostport, 2000, this);} catch (IOException e) {e.PrintStackTrace (}}} // actualizas The Znode Un nuevo UUID String.Public Void run () lanza interruptedException, KeeperException {while (true) {string uuid = uuid.randomuuid (). toString (); byte zoo_data [] = uuid.getBytes (); zk.setdata (zoodatapath, zoo_data, -1); try {thiftbytes (5000); // dormir para 5 segundos} capt (interruptedException e) {thread.currentThread (). Interrupt ();}}} public static void main (string [] args) shreatsioException, interruptedException, keepeException {dataUpdater dataUpdater = new dataUpdater (); dataUpdater.run ();}@overpidepreadeCeDeVent) {System.out.printf ("/NEVENT recibido: %S", event.ToString ());}}El código anterior hace que el servidor Zookeeper active un evento nodoDatachanged. Dado que DataWatcher establece el monitoreo de esta ruta Znode, recibe notificaciones de eventos de cambio de datos. Luego recupera los datos actualizados, restablece el monitoreo e imprime los datos en la consola.
Use el siguiente comando para compilar las clases de DataWatcher y DataUpdater:
$ javac cp $ classpath datawatcher.java $ javac cp $ classpath dataupdater.java
Para ejecutar el programa Monitor y Actualizar, se deben abrir dos ventanas de terminales. Primero quiero ejecutar el monitor porque crea el znode de /myconfig (si no se ha creado en el espacio de nombres de Zookeeper). Antes de ejecutar el monitor, asegúrese de que el servidor ZOOKEEper se ejecute en el host local.
En una de las ventanas de terminal, ejecute la clase de observador ejecutando el siguiente comando:
$ java cp $ classpath datawatcher
Emitir un mensaje similar al que se muestra en la siguiente captura de pantalla:
Como se muestra en la captura de pantalla anterior, la clase Znode Rath/MyConfig es creada por la clase DataWatcher. También imprime el contenido del Znode, pero no en la consola, porque no establecemos ningún dato al crear el ZNODE. Cuando se crea Znode, el monitor en la clase recibe una notificación de evento del tipo NodeCreated, que se imprime en la consola. La clase DataWatcher continúa ejecutándose y escucha eventos en el nodo /MyConfig desde el servidor ZOOKEEPER.
Ejecutemos la clase DataUpdater en otra ventana de terminal:
$ java -cp $ classpath dataUpdater
Después de registrar el mensaje de registro específico inicial de Zookeeper en la consola, la clase DataUpdater se ejecuta sin solicitar. Establece una nueva cadena UUID en el campo de datos de la ruta Zookeeper/MyConfig. Entonces, vea que cada 5 segundos, la salida que se muestra en la captura de pantalla a continuación se imprime en la ventana del terminal que ejecuta DataWatch:
DataWatcher también se puede probar utilizando el shell Zookeeper. Continúe ejecutando la clase DataWatcher en el terminal como antes, y llame al shell Zookeeper en otro terminal y ejecute el comando que se muestra en la siguiente captura de pantalla:
En el terminal donde se está ejecutando DataWatcher, se imprime el siguiente mensaje:
Tres ejemplos - Monitor de clúster
Los servicios populares proporcionados a través de Internet, como correo electrónico, plataformas de servicio de archivos, juegos en línea, etc., son atendidos por cientos o miles de servidores que están altamente disponibles en múltiples centros de datos, que a menudo están separados geográficamente. En dicho clúster, se configuran algunos nodos de servidor dedicados para monitorear la actividad de los servidores que alojan servicios o aplicaciones en la red de producción. En un entorno de computación en la nube, tales nodos de monitoreo que también se utilizan para administrar el entorno de la nube se denominan controladores de la nube. Un trabajo importante de estos nodos controladores es detectar fallas en los servidores de producción en tiempo real y notificar a los administradores en consecuencia, y tomar las medidas necesarias, como fallar sobre las aplicaciones en el servidor fallido a otro servidor, garantizar la tolerancia a las fallas y la alta disponibilidad.
En esta sección, utilizaremos la API del cliente Java Zookeeper para desarrollar un modelo minimalista de monitor de clúster distribuido. El uso del concepto Efemperal Znode de Zookeeper para construir este modelo de monitoreo es bastante simple y elegante, como se describe en los siguientes pasos:
Cada servidor de producción ejecuta un cliente Zookeeper como un demonio. Este proceso se conecta al servidor Zookeeper y crea un Znode efímero con un nombre (preferiblemente su nombre de red o nombre de host) bajo la ruta predefinida del espacio de nombres /Zookeeper (como /miembros). El nodo del controlador de la nube ejecuta el proceso del monitor Zookeeper, que monitorea las rutas/miembros y escucha eventos de tipo NodechildriDrilDenchanged. Este proceso de monitor se ejecuta como un servicio o demonio, y establece o restablece el monitoreo en la ruta, e implementa su lógica para llamar a los módulos apropiados para tomar las medidas necesarias para monitorear los eventos. Ahora, si el servidor de producción se apaga debido a una falla de hardware o un bloqueo de software, el proceso del cliente ZOOKEEPER finaliza, lo que provoca que la sesión entre el servidor y el servicio ZOOKEEPER se finalicen. Dado que las propiedades del znode efímero son únicas, el servicio Zookeeper eliminará automáticamente el zNode en la ruta/miembros siempre que la conexión del cliente esté cerrada. La eliminación de Znode en la ruta eleva el evento NodechildrildriRchanged, por lo que se notifica al proceso del observador en el controlador de la nube. Al llamar al método GetChildren en la ruta/miembros, puede determinar qué nodo del servidor se ha cerrado. El nodo del controlador puede tomar las medidas apropiadas, como realizar la lógica de recuperación para reiniciar el servicio fallido en otro servidor. Esta lógica se puede construir para funcionar en tiempo real, asegurando cerca de cero tiempo de inactividad y servicios altamente disponibles.
Para implementar este modelo de monitoreo de clúster, desarrollaremos dos clases de Java. La clase ClusterMonitor ejecutará continuamente el monitor para monitorear las rutas/miembros en el árbol Zookeeper. Después de procesar el evento elevado, imprimiremos la lista de Znode en la consola y restableceremos el monitoreo. Otra clase ClusterClient iniciará la conexión al servidor Zookeeper y creará un zNode efímero debajo /miembros.
Para simular un clúster con múltiples nodos, iniciamos múltiples clientes en la misma computadora y creamos un znode efímero utilizando la ID de proceso del proceso del cliente. Al ver la identidad del proceso, la clase ClusterMonitor puede determinar qué proceso del cliente se ha cerrado y qué procesos aún están allí. En casos prácticos, los procesos del cliente generalmente crean znode efímero utilizando el nombre de host del servidor en ejecución actualmente. Los códigos de origen para estas dos clases se muestran a continuación.
La clase ClusterMonitor.java se define de la siguiente manera:
import java.io.ioException; import java.util.list; import org.apache.zookeePer.CreatEmode; import org.apache.zookeePer.keePeexception; import.apache.zookeepers.watchedevent; importar.apache.zookeeper.watcher; import org.apache.zookeeper.ZooKeeper;public class ClusterMonitor implements Runnable {private static String membershipRoot = "/Members";private final Watcher connectionWatcher;private final Watcher childrenWatcher;private ZooKeeper zk;boolean alive=true;public ClusterMonitor(String HostPort) throws IOException, InterruptedException, KeeperException {connectionWatcher = new Watcher() {@OverridePublic Void Process (WatchedEvent Event) {if (event.gettype () == watcher.event.eventType.none && event.getState () == watcher.event.ekeeperstate.syncconnected) {system.printf ("/nevent recibido: %s", event.ToString ();}}; Watcher () {@OverridePublic Void Process (WatchedEvent Event) {System.out.printf ("/NEVEVE: %S", event.ToString ()); if (event.gettype () == event.eventType.nodeDeDelDrenChanged {thydlyren {intent {// obtener la lista actual de niños znode, // resete el watchlist <string> zk. MembreshipRoot, este); Wall ("¡Cambio de membresía de clúster!"); Wall ("Miembros:" + niños);} Catch (KeeperException e) {Throw New RuntimeException (E);} Catch (InterruptedException e) {Thread.CurrentThread (). Interrupt (); Alive = False; tostar NewTimeException (e);}}}}; ZOOKEEPER (HOSTPORT, 2000, ConnectionWatcher); // Asegúrese de que el ZNode principal exista (ZK.Exists (membresía, falso) == null) {zk.create (membershipRoot, "clustermonitorRoot" .getBytes (), ids.open_acl_unsafe, createMode.persistent);} ////set un reloj de plato en el patio ZnodeList <String> Children = Zk.getChildren (MembershipRoot, ChildrenWatcher); System.err.Println ("Members:" + Children);} public sincronizado sincronizado cerca () {try {zk.close ();} capt (interruptedException e) {E.PrintStackTrace ();}}} Public void Wall (string Message) {System.out.printf ("/nMessage: %s", mensaje);} public void run () {try {synChronized (this) {while (vivo) {wait ();}}} catch (interruptedException e) {e.PrintStace (); thread.currentThread (). void main (string [] args) lanza ioexception, interruptedException, keepreException {if (args.length! = 1) {system.err.println ("usege: clustermonitor <host: port>"); system.exit (0);} string host = args [0]; new clustermonitor (hostport) .run ();}}}}}}La clase ClusterClient.java se define de la siguiente manera:
import java.io.ioException; import java.lang.management.managementFactory; import org.apache.zookeeper.createMode; import org.apache.zookeeper.ekeeperException; importar org.apache.zookeepers.watchedEvent; importar org.apache.zookeeper.watcher; import; importar; import org.apache.zookeeper.zoodefs.ids; import org.apache.zookeepers.zookeeper; public class ClusterClient implementa Watcher, runnable {private static string membershipRoot = "/members"; Zookeeeper Zk; public ClusterClient (String HostPort, Long PID) {String ProcessId = PID.Tostring (); ZOOKEEPER (hostport, 2000, this);} catch (ioException e) {E.PrintStackTrace ();} if (zk! = Null) {try {zk.create (membershiproot + '/' + processId, processID.getBytes (), id.opere_acl_unsafe, createMode.ephemeral);} (} Catch (KeepAdtes (), IDS.Open_Acl_unsafe, createMode.ephemeral);} Catch (KeepArt (KeepAdExty | e) {E.PrintStackTrace ();}}} public sincronizado void Close () {try {zk.close ();} catch (interruptedException e) {e.PrintStActAtRace ();}}@overridePublic Void Process (WatchedEvent) {System.out.Printf ("/nevent recibió: %s", ", event (watchedEvent)) void run () {try {sincronizado (this) {while (true) {wait ();}}} capt (interruptedException e) {e.printstacktrace (); thread.currentThread (). {System.err.println("Usage: ClusterClient <Host:Port>");System.exit(0);}String hostPort = args[0];//Get the process idString name = ManagementFactory.getRuntimeMXBean().getName();int index = name.indexOf('@');Long processId = Long.parseLong(name.substring(0, index));new ClusterClient (hostport, processID) .run ();}}Use el siguiente comando para compilar estas dos clases:
$ javac -cp $ classpath clustermonitor.java $ javac -cp $ classpath clusterclient.java
Para ejecutar el modelo de monitoreo de clúster, abra dos terminales. En uno de los terminales, ejecute la clase ClusterMonitor. En otro terminal, se ejecutan múltiples instancias ejecutando la clase ClusterClient en segundo plano.
En el primer terminal, ejecute la clase ClusterMonitor:
$ java -cp $ classpath clustermonitorlocalhost: 2181
Como se muestra en el ejemplo anterior, ve el mensaje de registro de depuración de la API del cliente. Finalmente, la clase ClusterMonitor comienza a monitorear el evento e ingrese el siguiente contenido:
Ahora ejecute cinco instancias de la clase ClusterClient para simular cinco nodos de un clúster. ClusterClient crea un znode efímero utilizando su propia identificación de proceso en la ruta /miembros del árbol Zookeeper:
$ java -cp $ classpath clusterClient localhost: 2181 2> & 1>/dev/null & [1] 4028 $ java -cp $ classpath clusterClient localhost: 2181 2> & 1>/null & [2] 4045 $ java -cp $ classpath clusterclient localhost: 2181 2> & 1>/null & null java -cp $ classpath clusterClient localhost: 2181 2> & 1>/dev/null & [4] 4072 $ java -cp $ classpath clusterClient localhost: 2181 2> & 1>/dev/null & [5] 4084
En correspondencia con esto, se observará que la clase ClusterMonitor detecta estas nuevas instancias de clase ClusterClient, ya que está monitoreando los eventos en la ruta /miembros del árbol Zookeeper. Esto simula un evento de unión de nodo en un clúster real. La salida se puede ver en el terminal de la clase ClusterMonitor, que es similar a lo que se muestra en la captura de pantalla a continuación:
Ahora, si se mata un proceso ClusterClient.Java, se terminará la sesión que mantiene con el servidor ZOOKEEper. Por lo tanto, se eliminará el zNode efímero creado por el cliente. La eliminación activará el evento Nodechildrenchanged, que será capturado por la clase ClusterMonitor. Esto simula un escenario en el que un nodo sale en el clúster.
Terminemos el proceso ClusterClient con ID 4084:
$ Kill -9 4084
La siguiente captura de pantalla muestra la salida en el terminal de la clase ClusterMonitor. Enumera los procesos disponibles actualmente y sus ID de proceso que emulan el servidor en tiempo real:
La implementación de ejemplo del modelo de monitoreo de clúster simple y elegante anterior demuestra el verdadero poder de Zookeeper. Sin Zookeeper, desarrollar un modelo de este tipo que pueda monitorear la actividad del nodo en tiempo real sería una tarea realmente desalentadora.