Valkey en clúster: 3 principales, 3 réplicas y failover probado

Mascote LinuxPro encaixa um cubo de luz (hash slot) num servidor de um cluster Valkey de três racks, com o logo do Valkey na parede e o cachorro caramelo deitado ao lado

Un Valkey en solitario aguanta mucho, pero cuando cae se lleva por delante la caché, las sesiones y las colas de la aplicación. El modo cluster resuelve los dos problemas de una vez: reparte los datos entre varios primarios y deja una réplica lista para asumir cada porción cuando un servidor muere. En esta guía montamos un cluster con 3 primarios y 3 réplicas, tiramos un primario a propósito y medimos cuánto tiempo estuvieron paradas las escrituras. También añadimos y quitamos nodos, activamos persistencia, ACL y TLS, configuramos el servicio con systemd y conectamos el Valkey Admin al cluster. Todo se ejecutó de verdad en un laboratorio en Docker con Valkey 9.1.2, y las salidas mostradas a continuación salieron de esa prueba.

Qué es Valkey

En marzo de 2024 Redis Inc. cambió la licencia de Redis, que era BSD, por licencias source available. El día 28 de ese mes la La Linux Foundation anunció Valkey, un fork creado por antiguos mantenedores y colaboradores del proyecto a partir de Redis 7.2.4. Valkey continúa con la licencia BSD de 3 cláusulas y tiene gobernanza abierta. AWS, Google Cloud, Oracle, Ericsson y Snap han apoyado el proyecto desde el anuncio. El protocolo sigue siendo el mismo, por lo que los clientes y herramientas hechos para Redis en general funcionan sin cambios.

Versiones en 23/09/2026, consultadas en las releases de GitHub y en la página de descargas:

  • 9.1.2 (31/08/2026): estable actual. Es una release de seguridad que corrige dos use-after-free (uno de ellos en el estado del intérprete Lua, explotable sin autenticación) y decenas de errores, varios de ellos de cluster y de migración de slots. Actualice.
  • 9.0.6 e 8.1.10 (01/09/2026): últimas correcciones de las series anteriores que aún reciben soporte.
  • 9.2.0-rc1 (16/09/2026): release candidate. No usar en producción.

Novedades de las dos últimas versiones mayores que cambian la operación de un cluster, según los anuncios oficiales del Valkey 9.0 y de Valkey 9.1:

  • Migración atómica de slots (9.0): el resharding pasa a mover el slot completo, y no clave por clave. El nodo de origen mantiene todos los datos hasta el final de la migración, lo que evita las redirecciones intermedias y la congelación con claves muy grandes. El comando es CLUSTER MIGRATESLOTS, que usamos más adelante.
  • Bases de datos numeradas en modo clúster (9.0): SELECT 1 pasó a funcionar en clúster. En Redis y en las versiones anteriores de Valkey, el clúster solo aceptaba la db 0.
  • Expiración por campo de hash (9.0): comandos como HEXPIRE, HSETEX e HGETEX.
  • Clústeres grandes (9.0): el proyecto informa de una escala de hasta 2.000 nodos y más de 1 mil millones de peticiones por segundo.
  • ACL por base de datos (9.1): ACL SETUSER app ... db=0,1 restringe un usuario a algunas bases de datos.
  • Lua como módulo (9.1): Lua salió del núcleo y se puede desactivar cuando no se utiliza.
  • TLS (9.1): recarga automática de los certificados, fecha de expiración en INFO y autenticación por SAN URI.
  • Log en JSON (9.1): log-format json no valkey.conf.
  • Memoria y rendimiento (9.1): las cadenas pequeñas utilizan hasta 20% menos memoria, hay un nuevo modelo de hilos de I/O y los nuevos comandos HGETDEL e MSETEX.

Cómo funciona el cluster

Valkey Cluster divide el espacio de claves en 16384 hash slots. El slot de una clave es CRC16(chave) mod 16384, y cada primario es dueño de un rango de slots. Con 3 primarios, la división por defecto queda así: 0–5460, 5461–10922 y 10923–16383. Cada primario tiene una o más réplicas, que reciben los datos por replicación asíncrona y quedan listas para asumir.

  • Bus del cluster (cluster bus): además del puerto de los clientes, cada nodo abre un segundo puerto TCP, que por defecto es el puerto del cliente más 10000 (16379). Por él los nodos intercambian gossip binario, es decir, PING/PONG con el estado de cada nodo, el mapa de slots y los votos de failover.
  • Detección de fallo: si un nodo deja de responder durante más de cluster-node-timeout, quien lo detecta lo marca como PFAIL (fallo probable). Cuando la mayoría de los primarios reporta lo mismo, se convierte en FAIL y esa información se propaga por el clúster.
  • Failover automático: la réplica del primario en FAIL pide votos a los demás primarios. Con la mayoría de los votos, se promueve, incrementa el config epoch y pasa a servir los slots del primario que cayó.
  • MOVED: cuando el cliente pide una clave a un nodo que no es dueño del slot, recibe MOVED <slot> <ip:porta>. Um cliente cluster-aware actualiza el mapa de slots y va directo al nodo correcto.
  • ASK: aparece mientras un slot está migrando y la clave ya ha ido al destino. La redirección vale solo para esa petición, y el cliente no actualiza el mapa.
  • Hash tags: cuando la clave tiene {...}, solo el trecho entre llaves entra en el cálculo del slot. {pedido:42}:itens e {pedido:42}:total caen en el mismo slot y pueden usarse juntas en MSET, transacciones y scripts.

Topologia de um cluster Valkey com três shards, cada um com um primário e uma réplica, ligados pelo barramento do cluster na porta 16379

¿Cluster o Sentinel?

Las dos opciones ofrecen alta disponibilidad, pero resuelven problemas diferentes:

Sentinel Cluster
Datos Un único primario con el conjunto de datos completo Conjunto de datos dividido entre varios primarios (sharding)
Escala de escritura La de un servidor Crece con el número de primarios
Failover Procesos valkey-sentinel separados votan y promueven a la réplica Los propios nodos votan por el bus
Cliente Pregunta a Sentinel quién es el primario Necesita entender MOVED/ASK (modo cluster)
Comandos multi-clave Libres Solo con claves en el mismo slot (hash tags)
Bases de datos numeradas Sí a partir de Valkey 9.0

Si el dataset cabe en un único servidor y la aplicación depende de muchos comandos multi-clave, el Sentinel es más sencillo. Si necesitas más memoria o más caudal de escritura de los que ofrece una sola máquina, el camino es el cluster.

Requisitos y puertos

  • Mínimo de 3 primarios. A documentación recomienda 6 nodos (3 primarios y 3 réplicas), y cada primario debe estar en una máquina distinta de su réplica.
  • TCP 6379 (clientes y replicación) y TCP 16379 (bus) abiertos entre todos los nodos. Los clientes deben alcanzar la 6379 de todos los nodos, y no solo de uno.
  • Sin NAT ni reasignación de puertos. El cluster anuncia su propia IP y su propio puerto, y Docker con -p 7000:6379 rompe las redirecciones. En el laboratorio de abajo usamos una red bridge con IP fija por contenedor y sin publicar puertos. En Kubernetes, usa cluster-announce-ip/cluster-announce-hostname o el Helm chart oficial.
  • El bus no autentica mensajes. Según la documentación, el puerto 16379 acepta lo que llegue. Protégelo con un cortafuegos que solo permita las IPs de los nodos, o con mTLS (tls-cluster yes).

Laboratorio con Docker: 6 nodos en 5 minutos

El laboratorio usa la imagen oficial valkey/valkey:9.1.2 en una red bridge dedicada, y cada nodo recibe una IP fija. Si necesitas un repaso sobre contenedores, consulta la historia de Docker. Empieza por el archivo de configuración que los seis nodos compartirán:

mkdir -p ~/valkey-lab && cd ~/valkey-lab
cat > valkey.conf <<'EOF'
port 6379
bind 0.0.0.0
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
save 900 1 300 10
dir /data
EOF

docker network create --subnet 10.77.77.0/24 valkey-net

for i in 1 2 3 4 5 6; do
  docker run -d --name valkey-$i --hostname valkey-$i \
    --network valkey-net --ip 10.77.77.1$i \
    -v "$PWD/valkey.conf:/usr/local/etc/valkey/valkey.conf:ro" \
    valkey/valkey:9.1.2 valkey-server /usr/local/etc/valkey/valkey.conf
done

# contêiner "cliente" na mesma rede, para rodar valkey-cli e testes
docker run -d --name valkey-client --network valkey-net --ip 10.77.77.30 \
  valkey/valkey:9.1.2 sleep infinity

O protected-mode no sin contraseña solo sirve para el laboratorio aislado. La sección de seguridad muestra lo que cambia en producción. Antes de crear el clúster, un nodo recién iniciado rechaza escrituras:

$ docker exec valkey-1 valkey-cli set foo bar
CLUSTERDOWN Hash slot not served

Crea el clúster con una réplica por primario:

docker exec valkey-client valkey-cli --cluster create \
  10.77.77.11:6379 10.77.77.12:6379 10.77.77.13:6379 \
  10.77.77.14:6379 10.77.77.15:6379 10.77.77.16:6379 \
  --cluster-replicas 1 --cluster-yes
>>> Performing hash slots allocation on 6 node(s)...
Primary[0] -> Slots 0 - 5460
Primary[1] -> Slots 5461 - 10922
Primary[2] -> Slots 10923 - 16383
Adding replica 10.77.77.15:6379 to 10.77.77.11:6379
Adding replica 10.77.77.16:6379 to 10.77.77.12:6379
Adding replica 10.77.77.14:6379 to 10.77.77.13:6379
...
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

CLUSTER INFO y CLUSTER NODES

$ docker exec valkey-client valkey-cli -h 10.77.77.11 cluster info | head -12
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_nodes_pfail:0
cluster_nodes_fail:0
cluster_voting_nodes_pfail:0
cluster_voting_nodes_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6

$ docker exec valkey-client valkey-cli -h 10.77.77.11 cluster nodes
63fa7320... 10.77.77.12:6379@16379 master - 0 1790176949000 2 connected 5461-10922
6e304101... 10.77.77.14:6379@16379 slave 5eaf881d... 0 1790176949520 3 connected
4bc5ee75... 10.77.77.15:6379@16379 slave accd0471... 0 1790176949000 1 connected
accd0471... 10.77.77.11:6379@16379 myself,master - 0 0 1 connected 0-5460
57d5706c... 10.77.77.16:6379@16379 slave 63fa7320... 0 1790176948000 2 connected
5eaf881d... 10.77.77.13:6379@16379 master - 0 1790176948818 3 connected 10923-16383

En cada línea de CLUSTER NODES aparecen el ID del nodo, ip:porta@porta-do-barramento, el rol, el primario que replica (en el caso de las réplicas), el config epoch y los rangos de slots. Los IDs se han acortado aquí. El valkey-cli --cluster check 10.77.77.11:6379 muestra la misma información en un formato más fácil de leer y avisa sobre slots abiertos o descubiertos.

Probando: MOVED, -c, CROSSSLOT y hash tags

$ C="docker exec valkey-client valkey-cli"

$ $C -h 10.77.77.11 set usuario:1000 nilton
MOVED 7319 10.77.77.12:6379

$ $C -h 10.77.77.11 cluster keyslot usuario:1000
(integer) 7319

$ $C -c -h 10.77.77.11 set usuario:1000 nilton     # -c segue o redirecionamento
OK
$ $C -c -h 10.77.77.11 get usuario:1000
"nilton"

$ $C -c -h 10.77.77.11 mset a 1 b 2
CROSSSLOT Keys in request don't hash to the same slot

$ $C -h 10.77.77.11 cluster keyslot '{pedido:42}:itens'
(integer) 2873
$ $C -h 10.77.77.11 cluster keyslot '{pedido:42}:total'
(integer) 2873
$ $C -c -h 10.77.77.11 mset '{pedido:42}:itens' 3 '{pedido:42}:total' 99.90
OK

O -c no resuelve el CROSSSLOT, porque el comando necesita ejecutarse entero en un único nodo. Para cargar datos de prueba, el valkey-benchmark tiene modo clúster:

docker exec valkey-client valkey-benchmark -h 10.77.77.11 --cluster \
  -t set,get -n 100000 -r 100000 -q

for i in 1 2 3; do docker exec valkey-$i valkey-cli dbsize; done
# 34705 / 32366 / 32931 chaves: distribuição equilibrada entre os shards

Failover en la práctica: tirando un primario

Para medir el failover, un script en el contenedor cliente escribe la clave conta:1 cada 100 ms. La clave está en el slot 3844, que pertenece al primario 10.77.77.11. El script usa valkey-cli -c con timeout de 0,5 s por intento y anota cuándo falla la primera escritura y cuándo vuelven las escrituras:

cat > failover.sh <<'EOF'
#!/bin/bash
# Grava conta:1 (slot 3844) a cada 100 ms e mede quanto tempo as escritas falham.
ms() { date +%s%3N; }
falhou=0; n=0
while :; do
  n=$((n+1))
  r=$(timeout 0.5 valkey-cli -c -h 10.77.77.12 set conta:1 "$n" 2>&1)
  if [ "$r" != "OK" ]; then
    [ "$falhou" = 0 ] && falhou=$(ms) && echo "$(date +%T.%3N) primeira falha: ${r:-timeout}"
  elif [ "$falhou" != 0 ]; then
    echo "$(date +%T.%3N) escrita voltou; indisponivel por $(( $(ms) - falhou )) ms"; exit 0
  fi
  sleep 0.1
done
EOF
chmod +x failover.sh
docker cp failover.sh valkey-client:/failover.sh
docker exec -d valkey-client bash -c '/failover.sh > /failover.log 2>&1'
sleep 2; date -u +%T.%3N; docker kill valkey-1     # derruba o primário sem aviso
sleep 15; docker exec valkey-client cat /failover.log

El resultado con cluster-node-timeout 5000. El docker kill fue a las 15:23:07.013 (UTC):

15:23:07.589 primeira falha: timeout
15:23:13.216 escrita voltou; indisponivel por 5628 ms

El log de la réplica valkey-5 muestra la secuencia:

15:23:13.076 * FAIL message received from 63fa7320... (10.77.77.12:6379) about accd0471... (10.77.77.11:6379)
15:23:13.076 # Cluster state changed: fail
15:23:13.076 * This is the best ranked replica and can initiate the election immediately.
15:23:13.076 * Starting a failover election for epoch 7, node config epoch is 1
15:23:13.079 * Failover election won: I'm the new primary.
15:23:13.079 * configEpoch set to 7 after successful failover

Entre la muerte del primario y la vuelta de las escrituras pasaron unos 6,2 s. Casi todo ese tiempo fue el cluster-node-timeout (5 s) sumado a la propagación de la FAIL mediante gossip. La elección llevó 3 ms. Repetimos la prueba con el timeout en 2000 ms (CONFIG SET cluster-node-timeout 2000 en todos los nodos), derribando al nuevo primario. El FAIL salió 2,99 s después del kill y las escrituras volvieron en unos 3,1 s.

Linha do tempo do failover medido no laboratório com cluster-node-timeout de 5000 e 2000 ms

Un timeout menor no sale gratis. Una pausa larga de red o de disco, como un fork grande para el RDB, puede disparar un failover innecesario. Entre 2 y 5 segundos es un rango razonable en red local, pero mida en su entorno. Tras el failover, el antiguo primario vuelve como réplica del nodo promovido:

$ docker start valkey-1
$ docker exec valkey-client valkey-cli -h 10.77.77.12 cluster nodes | grep -E '1[15]:'
accd0471... 10.77.77.11:6379@16379 slave 4bc5ee75... 0 1790177013144 7 connected
4bc5ee75... 10.77.77.15:6379@16379 master - 0 1790177012000 7 connected 0-5460

Para devolver el rol de primario, sin perder escrituras, ejecute CLUSTER FAILOVER en la réplica. El failover manual espera a que la réplica alcance el offset del primario antes de cambiar los roles. Es el procedimiento correcto para actualizar la versión nodo a nodo:

docker exec valkey-client valkey-cli -h 10.77.77.11 cluster failover
docker exec valkey-client valkey-cli -h 10.77.77.11 role | head -1   # master

Añadiendo nodos, rebalance y eliminación

Levante dos nodos nuevos con la misma configuración (valkey-7 en 10.77.77.17 y valkey-8 en 10.77.77.18). Uno entra como primario vacío y el otro como su réplica:

C="docker exec valkey-client valkey-cli"
$C --cluster add-node 10.77.77.17:6379 10.77.77.11:6379
$C --cluster add-node 10.77.77.18:6379 10.77.77.11:6379 --cluster-replica
# sem --cluster-primaries-id, a réplica é associada ao primário com menos réplicas (o novo)

El nuevo primario entra sin slots. El rebalance distribuye los slots a partes iguales, y --cluster-use-empty-primaries es lo que hace que considere los primarios vacíos:

$ time $C --cluster rebalance 10.77.77.11:6379 --cluster-use-empty-primaries
>>> Rebalancing across 4 nodes. Total weight = 4.00
Moving 1366 slots from 10.77.77.12:6379 to 10.77.77.17:6379
Moving 1365 slots from 10.77.77.13:6379 to 10.77.77.17:6379
Moving 1365 slots from 10.77.77.11:6379 to 10.77.77.17:6379
real  0m6,472s

$ $C --cluster info 10.77.77.11:6379
10.77.77.11:6379 (accd0471...) -> 26018 keys | 4096 slots | 1 replicas.
10.77.77.17:6379 (7149edd5...) -> 24991 keys | 4096 slots | 1 replicas.
10.77.77.13:6379 (5eaf881d...) -> 24782 keys | 4096 slots | 1 replicas.
10.77.77.12:6379 (63fa7320...) -> 24212 keys | 4096 slots | 1 replicas.
[OK] 100003 keys in 4 primaries.

Para mover un rango específico existe el --cluster reshard (--cluster-from, --cluster-to, --cluster-slots). En Valkey 9 también se puede usar la migración atómica directa, y fue así como vaciamos el nodo 17 antes de eliminarlo. El comando se envía al nodo de origen, con un rango por destino:

$ $C -h 10.77.77.17 cluster migrateslots \
    slotsrange 0 1364 node accd0471d25a3d53a1a66c41971d01adacdbbe70 \
    slotsrange 5461 6826 node 63fa7320b3a4524df08a5925ab94962b08b5c5e0 \
    slotsrange 10923 12287 node 5eaf881d4c3e5720ccf7cc369540e57ed00decfe
OK
$ $C -h 10.77.77.17 cluster getslotmigrations   # state: success em cada job

Detalle observado en la prueba: tras perder todos los slots, el nodo 17 se reconfiguró solo como réplica de otro primario. Es la migración de réplicas (cluster-allow-replica-migration, activada por defecto). Con el nodo vacío, elimina primero la réplica y después el antiguo primario:

$C --cluster del-node 10.77.77.11:6379 <id-do-valkey-8>
$C --cluster del-node 10.77.77.11:6379 <id-do-valkey-7>
$C --cluster check 10.77.77.11:6379
# [OK] 100003 keys in 3 primaries.  [OK] All 16384 slots covered.

Ninguna llave se perdió en el ajetreo: 100003 antes y 100003 después. Para el --cluster call, que ejecuta el mismo comando en todos los nodos, vea el truco de la sección de solución de problemas.

Persistencia: RDB y AOF

En el clúster, cada nodo persiste solo sus propias ranuras. Las opciones son las mismas que en Valkey independiente (documentación):

  • RDB (save 900 1 300 10): snapshot periódico, compacto, bueno para copia de seguridad. Puede perder las escrituras realizadas desde el último snapshot.
  • AOF (appendonly yes, appendfsync everysec): registra cada escritura y se pierden como máximo unos 1 s. Desde Redis 7 el AOF es multiparte: un base.rdb, un incr.aof y un manifiesto.
$ docker exec valkey-1 ls /data /data/appendonlydir
/data:
appendonlydir  nodes.conf
/data/appendonlydir:
appendonly.aof.2.base.rdb  appendonly.aof.2.incr.aof  appendonly.aof.manifest

$ docker restart valkey-1 valkey-2 valkey-3 valkey-4 valkey-5 valkey-6
$ docker exec valkey-client valkey-cli --cluster info 10.77.77.11:6379 | tail -2
[OK] 100003 keys in 3 primaries.

O nodes.conf no es copia de seguridad de datos. Es el estado del clúster (IDs, epochs, ranuras), escrito por el propio Valkey, y no debe editarse a mano. Guárdelo junto a la copia de seguridad, pero no lo copie a otro nodo. En caché pura se pueden desactivar los dos (save "" e appendonly no). En ese caso la réplica es la única copia, y un nodo que se reinicia vuelve vacío y sincroniza todo de nuevo.

Seguridad: protected-mode, contraseña, ACL y TLS

protected-mode

Si el usuario default no tiene contraseña y el protected-mode está activado (por defecto), Valkey sólo acepta conexiones a través del loopback. Un cliente remoto recibe:

DENIED Running in protected mode because protected mode is enabled and no password is set for the default user. In this mode connections are only accepted from the loopback interface. ...

La salida no es desactivar la protección. Es establecer contraseña, o usuarios ACL, y mantener la bind en las IPs internas.

Contraseña del cluster y autenticación entre réplica y primario

En el clúster, las réplicas también se autentican en el primario, y por eso requirepass necesita ir junto con primaryauth (el antiguo masterauth). En el laboratorio aplicamos ambas con CONFIG SET y reiniciamos una réplica. Como el archivo montado era de sólo lectura, la configuración no persistió, y la réplica volvió sin primaryauth:

master_link_status:down
# Unexpected reply to PSYNC from primary: -NOAUTH Authentication required.
# PRIMARY aborted replication with an error: NOAUTH Authentication required.

Coloque las dos directivas en valkey.conf de todos los nodos, y no sólo vía CONFIG SET. Con contraseña, las herramientas de clúster reciben -a (o --user/--pass):

valkey-cli -a 'SenhaForte' --no-auth-warning --cluster check 10.77.77.11:6379

ACL por aplicación

Las ACL no se replican por el bus. Cree el usuario en cada nodo, o mantenga un aclfile igual en todos:

for i in 11 12 13 14 15 16; do
  valkey-cli -a 'SenhaForte' --no-auth-warning -h 10.77.77.$i \
    ACL SETUSER app on '>S3nhaApp!' '~app:*' '+@read' '+@write' '-@dangerous'
done

$ valkey-cli -c -h 10.77.77.11 --user app --pass 'S3nhaApp!' --no-auth-warning set app:config 1
OK
$ valkey-cli -c -h 10.77.77.11 --user app --pass 'S3nhaApp!' --no-auth-warning set outro:x 1
NOPERM No permissions to access a key
$ valkey-cli -c -h 10.77.77.11 --user app --pass 'S3nhaApp!' --no-auth-warning flushall
NOPERM User app has no permissions to run the 'flushall' command

TLS en clientes, replicación y bus

La imagen oficial y el binario oficial ya vienen con TLS. Probamos un clúster separado de 3 nodos solo con TLS, usando una CA propia y un certificado con las IPs en el SAN:

openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -subj "/CN=Valkey CA" -out ca.crt
openssl genrsa -out valkey.key 2048
openssl req -new -key valkey.key -subj "/CN=valkey-cluster" -out valkey.csr
printf "subjectAltName=IP:10.77.77.21,IP:10.77.77.22,IP:10.77.77.23\nextendedKeyUsage=serverAuth,clientAuth\n" > ext.cnf
openssl x509 -req -in valkey.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -days 825 -sha256 -extfile ext.cnf -out valkey.crt
# valkey.conf (trecho TLS)
port 0                  # desliga a porta sem TLS
tls-port 6379
tls-cert-file /tls/valkey.crt
tls-key-file /tls/valkey.key
tls-ca-cert-file /tls/ca.crt
tls-cluster yes         # barramento do cluster com TLS
tls-replication yes     # replicação com TLS
tls-auth-clients yes    # exige certificado do cliente (mTLS)
T="--tls --cacert /tls/ca.crt --cert /tls/valkey.crt --key /tls/valkey.key"
valkey-cli $T --cluster create 10.77.77.21:6379 10.77.77.22:6379 10.77.77.23:6379 --cluster-yes
valkey-cli $T -c -h 10.77.77.21 set tls:ok sim     # OK
valkey-cli $T -c -h 10.77.77.22 get tls:ok         # "sim"

valkey-cli -h 10.77.77.21 ping                          # Error: Connection reset by peer
valkey-cli --tls --cacert /tls/ca.crt -h 10.77.77.21 ping   # Error: Server closed the connection

El primer fallo es un cliente sin TLS hablando con el puerto TLS. El segundo es un cliente con TLS pero sin certificado propio, rechazado por tls-auth-clients yes. En producción, genere un certificado por nodo. Para más contexto sobre certificados, vea SSL/TLS en Postfix y en Dovecot.

En servidores reales: binario oficial y systemd

Opciones de instalación en Ubuntu y en Debian en septiembre de 2026:

  • Binario oficial en valkey.io/download: tarballs para Ubuntu 22.04 (jammy) y 24.04 (noble), en x86_64 y arm64, con la versión más reciente (9.1.2). Es lo que usamos a continuación.
  • Paquete de la distribución: Ubuntu 26.04 LTS trae 9.0.4 (apt install valkey-server valkey-tools, probado), Debian 13 trae 8.1.1 y Ubuntu 24.04 aún está en 7.2.x. Los paquetes ya incluyen las units valkey-server.service e valkey-server@.service.

En los seis servidores (aquí 10.0.0.11 a 10.0.0.16), ajuste el kernel como la documentación de administración recomienda:

echo 'vm.overcommit_memory = 1' | sudo tee /etc/sysctl.d/90-valkey.conf
sudo sysctl --system
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled   # persista via unit ou GRUB

Instala el binario comprobando el SHA-256 y crea el usuario, los directorios y la configuración:

VER=9.1.2
cd /tmp
curl -fsSLO https://download.valkey.io/releases/valkey-${VER}-noble-x86_64.tar.gz
curl -fsSLO https://download.valkey.io/releases/valkey-${VER}-noble-x86_64.tar.gz.sha256
sha256sum -c valkey-${VER}-noble-x86_64.tar.gz.sha256      # ...tar.gz: OK
tar xzf valkey-${VER}-noble-x86_64.tar.gz
sudo install -m 755 valkey-${VER}-noble-x86_64/bin/* /usr/local/bin/

sudo useradd --system --home-dir /var/lib/valkey --shell /usr/sbin/nologin valkey
sudo install -d -o valkey -g valkey -m 750 /var/lib/valkey /var/log/valkey
sudo install -d -o root -g valkey -m 750 /etc/valkey
# /etc/valkey/valkey.conf  (troque o IP do bind em cada servidor)
bind 10.0.0.11 127.0.0.1
port 6379
protected-mode yes
daemonize no
supervised systemd
dir /var/lib/valkey
logfile /var/log/valkey/valkey.log
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
save 3600 1 300 100
requirepass Troque-Esta-Senha
primaryauth Troque-Esta-Senha
maxmemory 2gb
maxmemory-policy noeviction
sudo chown root:valkey /etc/valkey/valkey.conf
sudo chmod 640 /etc/valkey/valkey.conf

En clúster, maxmemory-policy noeviction hace que el nodo rechace escrituras cuando se agota la memoria, en lugar de borrar datos. Para uso solo como caché, cámbialo por allkeys-lru. La unit de systemd utiliza Type=notify, porque el binario oficial está compilado con soporte para systemd y avisa cuando está listo. Para los comandos del día a día de systemd, consulta Dominando systemd.

# /etc/systemd/system/valkey.service
[Unit]
Description=Valkey (cluster node)
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
User=valkey
Group=valkey
ExecStart=/usr/local/bin/valkey-server /etc/valkey/valkey.conf
Restart=on-failure
LimitNOFILE=65535
TimeoutStartSec=60
TimeoutStopSec=60
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/valkey /var/log/valkey /etc/valkey

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now valkey
systemctl status valkey     # Active: active (running) ... Status: "Ready to accept connections"

No hace falta ExecStop. systemd envía SIGTERM, y Valkey realiza el fsync del AOF, escribe la instantánea RDB final y guarda el nodes.conf antes de salir. En la prueba, el registro mostró “Saving the final RDB snapshot before exiting” e “Valkey is now ready to exit”. El /etc/valkey entra en ReadWritePaths para el caso de que utilices CONFIG REWRITE. Libera los puertos solo para la red de los nodos y de los clientes:

sudo ufw allow from 10.0.0.0/24 to any port 6379,16379 proto tcp

Por último, desde cualquiera de los servidores:

valkey-cli -a 'Troque-Esta-Senha' --no-auth-warning --cluster create \
  10.0.0.11:6379 10.0.0.12:6379 10.0.0.13:6379 \
  10.0.0.14:6379 10.0.0.15:6379 10.0.0.16:6379 --cluster-replicas 1

Replicar esto en seis máquinas es trabajo para automatización. La guía de Ansible cubre lo básico para convertir los pasos anteriores en un playbook.

Valkey Admin: el cluster en una pantalla

O Valkey Admin es la herramienta oficial de observación y gestión del proyecto, con licencia Apache 2.0. La versión 1.0 salió en mayo de 2026 y la actual es la 1.1.1 (14/08/2026). Funciona como aplicación de escritorio para Linux (.deb y AppImage) y macOS, o como aplicación web en Docker/Kubernetes. Entre las características se encuentran panel de memoria, CPU, clientes y hit ratio, navegador de claves, envío de comandos con autocompletado, mapa de topología del cluster, hot keys, big keys (novedad de la 1.1) y el COMMANDLOG agregado de todos los nodos.

En el laboratorio ejecutamos la versión web en la misma red del cluster, publicada solo en localhost:

docker run -d --name valkey-admin --network valkey-net --ip 10.77.77.60 \
  -p 127.0.0.1:18080:8080 \
  -e DEPLOYMENT_MODE=Web \
  -e VALKEY_HOST=10.77.77.11 -e VALKEY_PORT=6379 \
  -e VALKEY_AUTH_TYPE=password -e VALKEY_USERNAME=default \
  -e 'VALKEY_PASSWORD=SenhaForte' \
  valkey/valkey-admin:1.1.1

docker logs valkey-admin
# Server running at http://localhost:8080
# Starting metrics server for:  10-77-77-11-6379
# Starting metrics server for:  10-77-77-12-6379
# Starting metrics server for:  10-77-77-13-6379
# Cluster nodes and metrics servers are in sync

Las variables VALKEY_* inician la recopilación de métricas (un recopilador por primario), pero la interfaz comienza vacía. Abra http://127.0.0.1:18080, haga clic en + Add Connection y elija Discovery para clúster. Rellene host, puerto, usuario y contraseña. Atención: en nuestra prueba, la opción Use TLS apareció marcada por defecto en el modo Discovery, y la conexión se quedó parada en Connecting… hasta que desmarcamos la opción, ya que el clúster del laboratorio no usa TLS. Una vez conectado, el Cluster Topology mostró los 6 nodos con los pares primario/réplica correctos:

Tela Cluster Topology do Valkey Admin mostrando 3 primários e 3 réplicas do laboratório

Lee las limitaciones antes de ponerlo en producción:

  • No tiene login propio ni RBAC. Quien acceda a la interfaz puede ejecutar cualquier comando que permita la ACL del usuario configurado. Ponlo detrás de un proxy con autenticación (nginx, oauth2-proxy) y conéctate con un usuario ACL restringido.
  • No soporta mTLS. Solo TLS con contraseña. El cluster TLS con tls-auth-clients yes que montamos arriba no es compatible.
  • Las métricas vienen solo de los primarios, y el navegador de claves muestrea unas 1.000 claves (la búsqueda usa SCAN MATCH).

Monitorización

Valkey Admin es bueno para investigar problemas, pero las alertas son trabajo de Prometheus. El blog de Valkey tiene una guía de exporters que usa el redis_exporter, compatible con Valkey. Las alertas mínimas son cluster_state diferente de ok, master_link_status:down en las réplicas, memoria cerca del maxmemory y shard sin réplica. Si Prometheus aún no está activo, comience por Monitorizando Servidores Linux con Prometheus. Para una comprobación externa sencilla de TCP en 6379 de cada nodo, el Go Uptime resuelve.

Troubleshooting: errores que aparecieron en el laboratorio

  • CLUSTERDOWN Hash slot not served: el nodo está en modo clúster, pero ningún nodo es propietario del slot. Ocurre antes del --cluster create o cuando los slots quedaron sin propietario. Ejecute valkey-cli --cluster check y, si es el caso, --cluster fix.
  • CLUSTERDOWN The cluster is down: apareció un instante justo después del --cluster create en el clúster TLS, mientras los nodos convergían. Dos segundos después estaba ok. También aparece cuando un shard pierde el primario e la réplica. Derribamos los nodos 3 y 4 juntos, y cluster_slots_ok cayó a 10923. Con cluster-require-full-coverage no, los shards sanos siguen atendiendo y solo las claves del shard muerto fallan.
  • MOVED 7319 10.77.77.12:6379: cliente sin modo clúster. Usa valkey-cli -c o una biblioteca con soporte de clúster. Si el redireccionamiento apunta a una IP inalcanzable, el problema es NAT o cluster-announce-ip incorrecto.
  • ASK 3844 10.77.77.12:6379: reproducido marcando el slot como MIGRATING/IMPORTING a mano, en mitad de una migración clave a clave. El cliente con -c sigue solo. Si un slot se queda atascado en ese estado, el --cluster check acusa open slots, y el CLUSTER SETSLOT <slot> STABLE o el --cluster fix resuelven.
  • CROSSSLOT Keys in request don't hash to the same slot: comando multi-clave con claves en slots diferentes. Usa hashes ({pedido:42}:...).
  • master_link_status:down con NOAUTH en el log de la réplica: falta primaryauth en el nodo.
  • DENIED Running in protected mode: conexión remota sin contraseña en el usuario por defecto.
  • Unrecognized option or bad number of args for: '-@dangerous': el valkey-cli --cluster call interpreta argumentos que empiezan con - como opciones de la propia herramienta. Crea ACLs con un bucle por nodo, como se muestra arriba.
  • O AUTH failed no interrumpe el valkey-cli. Ese fue el susto del laboratorio. Ejecutamos comandos con --user app antes de que el usuario exista. O valkey-cli mostrou AUTH failed: WRONGPASS e continuou ejecutando los comandos como usuario default, que en aquel momento no tenía contraseña. Un FLUSHALL de prueba pasó y borró el shard 1 entero (cmdstat_flushall:calls=1 no INFO commandstats). Un motivo más para nunca dejar al usuario default sin contraseña.

Limpiando el laboratorio

docker rm -f valkey-{1..8} valkey-client valkey-admin 2>/dev/null
docker network rm valkey-net

Conclusión

Valkey heredó el clúster de Redis y viene mejorando exactamente la parte que más daba trabajo: el resharding se volvió atómico, el clúster admite bases de datos numeradas y la versión 9.1 trajo ACL por base de datos y TLS con rotación de certificados. En la prueba, el failover llevó cerca de 6 s con el cluster-node-timeout estándar del tutorial y cerca de 3 s con 2000 ms, sin intervención. Este número es el que debes llevar a la conversación con el equipo de la aplicación, junto con la exigencia de un cliente que entienda clúster. Si tu problema es alta disponibilidad de base de datos relacional, mira el clúster MariaDB Galera con mariabackup. Si el clúster se ejecutará en Kubernetes bare metal, el MetalLB resuelve la exposición de los servicios.