Para asegurar una operación coordinada y fiable en un sistema distribuido, los diferentes nodos que lo componen deben poder comunicarse y compartir información de estado de manera consistente. ZooKeeper, como servicio de coordinación centralizada, facilita esta interacción al permitir que los servidores de un clúster mantengan una visión unificada del estado del sistema, soportando arquitecturas que se extienden a través de múltiples redes y garantizando la coherencia.
La configuración de un ensemble de ZooKeeper se gestiona principalmente a través de un archivo, comúnmente denominado zoo.cfg. Este archivo define los parámetros operativos esenciales para cada instancia de ZooKeeper. A continuación, se muestra un ejemplo de configuración para establecer un clúster de tres nodos en una única máquina:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=./data
clientPort=2181
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445
Cada parámetro tiene un propósito específico:
-
tickTime: Es la unidad de tiempo básica en milisegundos que utiliza ZooKeeper. -
initLimit: Define el número detickTimeque un seguidor (follower) puede tardar en conectarse al líder (leader) durante la fase de inicio del ensemble. -
syncLimit: Establece el número detickTimeque un seguidor puede tardar en sincronizarse con el líder una vez que la conexión ha sido establecida. -
dataDir: Especifica la ruta al directorio donde ZooKeeper almacenará los datos de persistencia y los snapshots. -
clientPort: Es el puerto en el que este servidor ZooKeeper escuchará las conexiones entrantes de los clientes. -
server.N: Cada entradaserver.Ndefine un miembro individual del ensemble de ZooKeeper, dondeNes el identificador único del servidor. La sintaxis esID=hostname:puerto_quorum:puerto_eleccion.hostname: La dirección IP o nombre de host del servidor.puerto_quorum: El puerto TCP utilizado para la comunicación entre los miembros del quórum (sincronización y replicación).puerto_eleccion: El puerto TCP utilizado para la elección del líder cuando el ensemble necesita elegir uno nuevo.
Dado que en este ejemplo estamos ejecutando múltiples instancias de servidor en una sola máquina, es crucial que cada instancia utilice puertos distintos para
clientPort,puerto_quorumypuerto_eleccion. En un despliegue distribuido real, donde cada instancia reside en una máquina física diferente, los puertos del quórum y de elección pueden ser los mismos para todos los servidores.
Cada instancia de ZooKeeper en el ensemble requiere su propio directorio de datos y un identificador único. Estos directorios se utilizan para almacenar los logs de transacciones y los snapshots de datos. Para nuestro ejemplo de tres nodos, crearemos la siguiente estructura de directorios:
mkdir -p z1/data z2/data z3/data
Adicionalmente, cada servidor necesita un archivo llamado myid dentro de su dataDir que contenga el identificador único del servidor (el mismo N usado en la configuración server.N). Esto permite a cada instancia saber cuál es su rol en el conjunto.
echo 1 > z1/data/myid
echo 2 > z2/data/myid
echo 3 > z3/data/myid
Una vez que los directorios y los archivos myid están en su lugar, podemos iniciar cada servidor. Cada servidor leerá su archivo myid para determinar su identidad y luego usará la configuración en zoo.cfg para establecer los puertos y comenzar a escuchar. Para nuestro ejemplo, cada instancia tendrá su propia configuración adaptada al puerto de cliente:
z1.cfg:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=./z1/data
clientPort=2181
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445
z2.cfg:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=./z2/data
clientPort=2182
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445
z3.cfg:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=./z3/data
clientPort=2183
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445
Ahora, para iniciar cada servidor (asumiendo que los acrhivos zN.cfg están en el mismo directorio de trabajo):
# Iniciar el servidor 1
/ruta/a/zookeeper/bin/zkServer.sh start z1.cfg
# Iniciar el servidor 2
/ruta/a/zookeeper/bin/zkServer.sh start z2.cfg
# Iniciar el servidor 3
/ruta/a/zookeeper/bin/zkServer.sh start z3.cfg
Una vez que el ensemble está en funcionamiento, los clientes pueden conectarse a él utilizando la utilidad de línea de comandos zkCli.sh y especificando la lista de servidores a los que intentar conectarse:
/ruta/a/zookeeper/bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
La lista de servidores proporcionada en la cadena de conexión del cliente permite un mecanismo básico de balanceo de carga y tolerancia a fallos. El cliente intenta conectarse a un servidor de la lista de forma aleatoria. Si el primer intento falla, probará con el siguiente disponible. Esto permite distribuir las conexiones de los clientes entre los miembros del ensemble. Sin embargo, no proporciona control granular sobre qué servidor se selecciona. Por ejemplo, si un ensemble tiene servidores distribuidos geográficamente, un cliente en la Costa Este de EE. UU. podría configurarse para conectarse exclusivamente a los servidores de esa región, mientras que los clientes de la Costa Oeste harían lo mismo, asegurando así que los clientes se conecten a las instancias más cercanas para optimizar la latancia.