Fundamentos de Zookeeper
Definición
Zookeeper es un proyecto de código abierto desarrollaod bajo la fundación Apache, diseñado para ofrecer servicios de coordinación en entornos distribuidos. Su función principal es actuar como un servicio centralizado que permite gestionar la configuración, sincronización y nomenclatura entre múltiples nodos distribuidos.
Arquitectura interna
Desde una perspectiva de patrones de diseño, Zookeeper implementa el patrón observador. El sistema mantiene un repositorio de datos que interesa a múltiples clientes distribuidos. Los clientes pueden registrarse como observadores y, cuando el estado de los datos cambia, Zookeeper se encarga de notificar a todos los suscriptores para que reaccionen en consecuencia. Esta arquitectura se resume en dos componentes esenciales: un sistema de almacenamiento jerárquico y un mecanismo de notificaciones automáticas.
Características principales
- Topología maestro-esclavo: Un nodo actúa como líder (Leader) y los demás como seguidores (Follower).
- Tolerancia a fallos: El clúster sigue operativo mientras más de la mitad de los nodos estén disponibles. Por ello se recomienda usar un número impar de servidores.
- Consistencia global: Cada servidor mantiene una réplica idéntica de los datos, garantizando que cualquier cliente obtenga la misma información sin importar a qué nodo se conecte.
- Orden de actualizaciones: Las peticiones de un mismo cliente se procesan secuencialmente según su orden de envío (FIFO).
- Atomicidad: Cada operación de modificación se completa en su totalidad o falla completamente, sin estados intermedios.
- Actualización en tiempo real: Los clientes pueden acceder a los datos más recientes dentro de un margen temporal reducido.
Modelo de datos
La estructura de almacenamiento de Zookeeper se asemeja a un sistema de archivos jerárquico tipo árbol, similar al de Linux. Cada nodo del árbol se denomina ZNode, con capacidad de almacenar hasta 1MB de información por defecto. Cada ZNode posee una ruta única que lo identifica dentro del árbol.
Proceso de elección del líder
Elección inicial
Cuando el clúster arranca por primera vez, los nodos inician un proceso de votación para seleccionar un líder:
- El primer nodo (nodo 1) arranca y se vota a sí mismo. Al no alcanzar la mayoría necesaria (más del 50%), permanece en estado
LOOKING. - El segundo nodo (nodo 2) se inicia. Ambos intercambian información de votación. El nodo 1 detecta que el identificador (
myid) del nodo 2 es superior, por lo que transfiere su voto al nodo 2. Sin embargo, con solo 2 votos no se alcanza la mayoría, manteniéndose ambos enLOOKING. - El tercer nodo (nodo 3) entra en funcionamiento. Los nodos 1 y 2 cambian sus votos hacia el nodo 3, quien acumula 3 votos, superando el umbral de mayoría. El nodo 3 se convierte en
LEADING, mientras que los nodos 1 y 2 pasan aFOLLOWING. - El cuarto nodo arranca y encuentra que los nodos existentes ya no están en estado
LOOKING, por lo que acepta al líder actual y se une comoFOLLOWING. - El quinto nodo procede de igual manera, integrándose como seguidor.
Elección tras una falla
La elección de un nuevo líder también se activa cuando un nodo pierde comunicación con el líder actual o cuando se reinicia. Existen dos escenarios posibles:
- El clúster ya tiene líder: El nodo que intenta elegir simplemente recibe la información del líder vigente, se connecta a él y sincroniza su estado.
- No existe líder: Se inicia un proceso de votación basado en tres criterios jerárquicos:
Reglas de prioridad en la votación:
- Mayor
Epoch(número de período del líder) gana. - Si los
Epochson iguales, mayorZXID(identificador de transacción) gana. - Si
EpochyZXIDcoinciden, mayorSID(identificador de servidor) gana.
Conceptos clave en la votación:
- SID (Server ID): Identificador único de cada servidor en el clúster, equivalente al valor de
myid. - ZXID (ZooKeeper Transaction ID): Identificador que marca cada cambio de estado del servidor. Puede variar entre nodos dependiendo de la velocidad de procesamiento de peticiones.
- Epoch: Código que representa el período de mandato de cada líder. Se incrementa con cada nueva ronda de votación.
Despliegue del clúster Zookeeper
Para este despliegue se utilizarán tres servidores con la siguiente configuración:
| Dirección IP | Software |
|---|---|
| 192.168.9.210 | Zokoeeper |
| 192.168.9.120 | Zookeeper |
| 192.168.9.140 | Zookeeper |
Preparación del entorno
Ejecutar en todos los servidores:
# Deshabilitar firewall y SELinux
systemctl disable --now firewalld
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# Instalar Java JDK
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel
java -version
Instalación del paquete Zookeeper
En el servidor 192.168.9.210:
cd /opt
tar -zxf apache-zookeeper-3.6.4-bin.tar.gz
mv apache-zookeeper-3.6.4-bin /usr/local/zookeeper
Configuración del servicio
En el servidor 192.168.9.210, copiar y editar el archivo de configuración:
cd /usr/local/zookeeper/conf
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg
Contenido del archivo zoo.cfg:
# Intervalo de latido en milisegundos
tickTime=2000
# Tiempo máximo de conexión inicial (tickTime * 10 = 20s)
initLimit=10
# Tiempo límite de sincronización entre Leader y Follower (tickTime * 5 = 10s)
syncLimit=5
# Directorio de almacenamiento de datos
dataDir=/usr/local/zookeeper/data
# Directorio de logs
dataLogDir=/usr/local/zookeeper/logs
# Puerto de conexión para clientes
clientPort=2181
# Definición de nodos del clúster (formato: server.ID=host:puerto_sync:puerto_eleccion)
server.1=192.168.9.210:3188:3288
server.2=192.168.9.120:3188:3288
server.3=192.168.9.140:3188:3288
El formato de cada línea server se compone de:
- ID numérico: Identificador del servidor, debe coincidir con el contenido del archivo
myid. - host: Dirección IP o hostname del servidor.
- puerto_sync: Puerto usado por los Followers para intercambiar datos con el Leader.
- puerto_eleccion: Puerto empleado durante el proceso de elección de un nuevo Leader.
Crear directorios y asignar el identificador del nodo:
cd /usr/local/zookeeper
mkdir -p data logs
echo 1 > data/myid
Replicación a los demás servidores
Transferir el directorio completo a los otros dos servidores:
scp -r /usr/local/zookeeper root@192.168.9.120:/usr/local/
scp -r /usr/local/zookeeper root@192.168.9.140:/usr/local/
En el servidor 192.168.9.120, actualizar el myid:
echo 2 > /usr/local/zookeeper/data/myid
En el servidor 192.168.9.140, actualizar el myid:
echo 3 > /usr/local/zookeeper/data/myid
Puesta en marcha del clúster
Iniciar el servicio en los tres servidores:
cd /usr/local/zookeeper/bin
./zkServer.sh start
# Verificar que el puerto 2181 esté activo
ss -tlnp | grep 2181
Consultar el rol de cada nodo dentro del clúster:
./zkServer.sh status
El orden de arranque determina qué nodo asume el rol de Leader y cuáles quedan como Followers, dependiendo del mecanismo de elección descrito anteriormente.