Redis – Replicación y Automatic Failover con Sentinel

Redis proporciona un mecanismo asíncrono de Replicación, con el que podemos tener una o varias réplicas de lectura para aumentar la disponibilidad o repartir las lecturas entre más instancias mejorando el rendimiento, apoyándose en Sentinel para proporcionar Automatic Failover, sin necesidad de un Cluster, aunque nos cambiará la forma de conectarnos a Redis.

Continuando con nuestra serie sobre Redis, tras haber hablado recientemente sobre cómo instalar y configurar Redis en Ubuntu, y sobre los mecanismos de persistencia y durabilidad en Redis, llega el momento de tratar dos temas bastante importantes: La Replicación (1 Master + N Slaves) y el Automatic Failover son Sentinel.

Replicación con Redis (1 Master + N Slaves)

La Replicación en Redis ocurre de forma asíncrona y en una única dirección, desde el primario o master, a una o varias réplicas, permitiendo repartir la carga y aumentar el rendimiento de las lecturas, enviando las escrituras al primario o master y las lecturas a las diferentes réplicas.

Desde el punto de vista de la escalabilidad, podemos añadir más recursos (memoria, cpu, disco) a primario y réplicas, e incluso aumentar el número de réplicas. Pero teniendo en cuenta que tanto el primario como las réplicas tendrán que almacenar absolutamente todos los datos en memoria, y que Redis es single-thread, llegará un punto en que no podremos resolver nuestros problemas añadiendo más recursos, habremos llegado al tope. En ese caso, nuestra solución pasaría a ser Redis Cluster (que también tiene sus cosillas, sólo soporta db0, también cambia la forma de conectar, mayor esfuerzo de mantenimiento, etc.).

La Replicación de Redis funciona sobre todas las bases de datos de Redis, no sólo a db0.

Para arrancar una réplica, es suficiente con arrancar un nuevo servicio de Redis con la configuración replicaof indicando la dirección y puerto del primario o master. Esto producirá que el primario o master creará y enviará a la réplica un Snapshot (RDB), seguido de todos los comandos que ha recibido desde que se generó el RDB, para finalmente enviarle a través de un stream todos los sucesivos comandos.

A continuación se muestra dos comandos de ejemplo para arrancar manualmente dos réplicas de lectura sobre una mismo servidor, utilizando diferentes puertos.

sudo /usr/bin/redis-server --port 6380 --replicaof 127.0.0.1 6379 --pidfile /run/redis/redis-server-6380.pid --logfile /var/log/redis/redis-server-6380.log --dbfilename dump-6380.rdb --masterauth misecretpwd

sudo /usr/bin/redis-server --port 6390 --replicaof 127.0.0.1 6379 --pidfile /run/redis/redis-server-6390.pid --logfile /var/log/redis/redis-server-6390.log --dbfilename dump-6390.rdb --masterauth misecretpwd

Si lo quisiéramos crear dos réplicas de una manera formal, deberíamos seguir la instalación y configuración de Redis en dos servidores adicionales, y establecer el valor de replicaof en el redis.conf, así como de otras configuraciones que podamos necesitas como masterauth en caso de que el primario o master requiera autenticación.

Debido a que la Replicación en Redis es asíncrona, se podría producir que un cliente ejecutara un comando contra el primario, el servidor Redis le devolviera el ACK al cliente, y antes de que se sincronizara el cambio con las réplicas, el primario sufriese una caída. Para evitar situaciones como esta, el cliente puede utilizar el comando WAIT para quedarse en espera hasta que la modificación ha sido confirmada (ACK) por al menos un determinado número de réplicas.

El siguiente ejemplo ejecutar una escritura en Redis (SET) y se queda esperando 100ms o hasta que se ha replicado en al menos dos réplicas, devolviendo un entero que indica el número de réplicas con que ha sincronizado el cambio.

set user:100007 tom
wait 2 100

Automatic Failover con Sentinel

Redis Sentinel es un sistema distribuido, formado por múltiples instancias de Redis arrancadas en modo Sentinel, a las que llamaremos Sentinels. Este grupo de Sentinels, monitorizan al primario o master así como a las réplicas, y en caso de fallo del primario o master, promocionarán a la réplica que tenga los datos más actuales, consiguiendo así proporcionar un Failover Automático a la Replicación de Redis (alta disponibilidad en Redis sin necesidad de un Cluster), y permitiendo que los clientes se puedan reconectar y seguir trabajando con un impacto mínimo en el servicio.

La Replicación de Redis con Sentinel proporciona Alta Disponibilidad a todas las bases de datos de Redis, no sólo a db0.

Para que todo esto funcione bien, debemos utilizar clientes que soporten Sentinel, algo que no todas las librerías soportan, aunque las más importantes sí, y además incluso podría ser necesario que tuviéramos que controlar por código los failover, para en caso de error por failover, reconectarse al nuevo master y reintentar. Vamos, control de errores de toda la vida.

A continuación se muestra un ejemplo en Python, conectándose a Redis a través de Sentinel, forzando un failover, y comprobando como reconectando y volviendo a ejecutar la operación, funciona correctamente.

Por verlo más claro, esta sería la forma de conectarse a Redis con Sentinel desde Python, con una contraseña.

from redis.sentinel import Sentinel

sentinel = Sentinel([('127.0.0.1',26379),
                     ('127.0.0.1',26380),
                     ('127.0.0.1',26390)],
                   sentinel_kwargs={'password': misecretpwd})

host, port = sentinel.discover_master("mastername")
redis_client = redis.StrictRedis(
            host=host,
            port=port,
            password= misecretpwd
        )

redis_client.set("foo", "bar")

También sería posible, utilizar Sentinel para crear dos conexiones, una al maestro para escrituras, y otra a una réplica para lecturas, y así poder distribuir mejor la carga, y evitar tener nodos «vagos» que tienen un coste, los aprovechemos más, o los aprovechemos menos.

Para más info: Python – Sentinel Client

La forma de decidir si el primario de Redis está caído (y promocionar una réplica) es mediante una estrategia de Quorum, en la que un número suficiente (y configurable) de Sentinels confirman que otro servidor Redis está caído. Habitualmente se utiliza un número impar de Sentinels y se requiere como Quorum el entero inmediatamente superior a su mitad, es decir, con 3 Sentinels se requeriría 2 de Quorum (esto es lo más habitual), y con 5 Sentinels se requeriría 3 de Quorum, para evitar que pueda haber situaciones de empate. Por ejemplo, podríamos tener:

  • 1M + 2R + 3S: Un primario con dos réplicas de lectura, es decir, tres servidores Redis que también ejecutan Sentinel, y exigir que para alcanzar el Quorum estén de acuerdo al menos dos Sentinel.
  • 1M + 1R + 3S: Un primario con una réplica de lectura, ambos con Sentinel, y un tercer servidor que ejecute sólo Sentinel (hará de árbitro o witness), y exigir que para alcanzar el Quorum estén de acuerdo al menos dos Sentinel. Para mí es la opción recomendada, ya que al mantener sólo dos Redis, tenemos alta disponibilidad con automatic failover sin pagar el precio de un tercer Redis, que en caso de volúmenes grandes de datos podría ser una máquina con un coste relevante que nos podemos ahorrar.

Al final, un Sentinel es un proceso redis-server arrancado con la opción –sentinel, que escucha en otro puerto (habitualmente el puerto tcp-26379), y con una configuración concreta relacionada con el Sentinel.

A continuación se muestran tres comandos de ejemplo para arrancar manualmente tres Sentinels sobre una misma VM con Ubuntu en la que se ejecutan tres servicios de Redis, utilizando diferentes puertos, a modo de laboratorio:

redis-server ./sentinel-6379.conf --logfile /var/log/redis/sentinel-6379.log --sentinel &

redis-server ./sentinel-6380.conf --logfile /var/log/redis/sentinel-6380.log --sentinel &

redis-server ./sentinel-6390.conf --logfile /var/log/redis/sentinel-6390.log --sentinel &

Los ficheros de configuración de Sentinel de los comandos anteriores (sentinel.conf), contendrían algo similar a lo siguiente, donde es importante asignar un nombre lógico para el master (master-name), que utilizaremos posteriormente cuando ejecutemos comandos Sentinel.

  • port 26379
    Especifica el puerto que utilizará Sentinel, en nuestros tres ejemplos usaremos 26379, 26380, y 26390.
  • sentinel monitor master-name 127.0.0.1 6379 2
    Especifica cuál es el servicio Redis que actúa como primario o master, para poder monitorizarlo y descubrir todas sus réplicas de lectura. El último argumento indica que se consigue quorum con dos Sentinels.
  • sentinel down-after-milliseconds master-name 5000
    Especifica cuantos milisegundos debe estar indisponible una instancia, para considerarla como indisponible.
  • sentinel failover-timeout master-name 60000
  • sentinel auth-pass master-name misecretpwd
    La password del servicio Redis.

El contenido inicial del fichero de configuración de Sentinel quedaría similar a como se muestra a continuación. Importante, tener presente que es el contenido inicial, ya que Sentinel actualizará este fichero y lo irá cambiando a lo largo del tiempo (ej: al descubrir réplicas, al producirse un failover, etc.), no es un fichero estático.

port 26379
sentinel monitor master-name 127.0.0.1 6379 2
sentinel down-after-milliseconds master-name 5000
sentinel failover-timeout master-name 60000
sentinel auth-pass master-name misecretpwd

Así, una vez tenemos arrancados nuestros tres servicios de Redis y los tres correspondientes Sentinels, nos podríamos con redis-cli a cualquier Sentinel, y ejecutar comandos como los siguientes:

  • SENTINEL master master-name
    Devuelve información del primario o master
  • SENTINEL replicas master-name
    Devuelve información de las réplicas que están conectadas al primario o master.
  • SENTINEL sentinels master-name
    Devuelve información del resto de Sentinels
  • SENTINEL get-master-addr-by-name master-name
    Devuelve la dirección IP y puerto del servidor Redis que actúa como primario o master.
  • SENTINEL help
    Muestra ayuda de las diferentes opciones del comandos SENTINEL
  • HELP SENTINEL
    Muestra ayuda de las diferentes opciones del comandos SENTINEL

A continuación se muestra un ejemplo, en el que nos conectamos con redis-cli a un Sentinel, para seguidamente ejecutar un par de comandos Sentinel, para sabe qué servidor Redis es actualmente el primario o master, y para obtener información del resto de réplicas existentes.

A continuación se muestra un ejemplo de failover manual con el comando SENTINEL FAILOVER.

Instalación de Redis Sentinel

Podemos instalar Redis Sentinel, direntamente con APT, lo que nos creará el correspondiente servicio.

sudo apt-get install redis-sentinel -y

sudo systemctl enable redis-sentinel
sudo systemctl start redis-sentinel
sudo systemctl status redis-sentinel

La instalación creará un fichero de configuración de Sentinel (/etc/redis/sentinel.conf), similar al fichero de configuración de Redis e igualmente auto-documentado, que podremos revisar y editar para ajustar la configuración de Sentinel a nuestras necesidades. Ya vimos antes en este mismo Post algunas configuraciones a revisar.

El fichero de log de Sentines, por defecto es /var/log/redis/redis-sentinel.log, por si lo necesitásemos revisar.

Despedida y Cierre

Hasta aquí llega este Post, en el que hemos intentado explicar el funcionamiento y configuración de la Replicación asíncrona de Redis, así la solución de Automatic Failover con Sentinel (sin necesidad de un Cluster) que nos proporciona Alta Disponibilidad a la Replicación, con el pequeño inconveniente de que cambia la forma de conectarse a Redis con Sentinel, y conscientes de los límites de escalabilidad de Replicación+Sentinel, ya que aunque podemos proporcionar más recursos (RAM, CPU, Disco) a primario y réplicas e incluso aumentar el número de réplicas, Redis es single-thread y en caso de grandes volúmenes de datos llegará un momento que no podremos proporcionar más recursos a nuestras máquinas porque habremos alcanzado un tope. Si llegamos a este punto, nuestra solución pasaría a ser Redis Cluster (que también tiene sus cosillas, sólo soporta db0, también cambia la forma de conectar, mayor esfuerzo de mantenimiento, etc.).

Para más información: High availability with Redis Sentinel

Poco más por hoy. Como siempre, confío que la lectura resulte de interés.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

9 − tres =