← Volver al listado de tecnologías

Clustering en Valkey

Por: Artiko
valkeyclustershardingescalabilidad

Clustering

¿Por qué Cluster?

Arquitectura del Cluster

┌─────────────────────────────────────────────────┐
│                  Hash Slots                      │
│            (16384 slots totales)                │
├─────────────┬─────────────┬─────────────────────┤
│ 0-5460      │ 5461-10922  │ 10923-16383         │
│ Nodo A      │ Nodo B      │ Nodo C              │
│ + Replica   │ + Replica   │ + Replica           │
└─────────────┴─────────────┴─────────────────────┘

Cada clave se mapea a un slot: HASH_SLOT = CRC16(key) mod 16384

Configuración mínima

Crear nodos del cluster

# Crear directorios para cada nodo
mkdir -p cluster/{7000,7001,7002,7003,7004,7005}

# Configuración base para cada nodo
cat > cluster/7000/valkey.conf << EOF
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
appendfilename "appendonly.aof"
dir ./
EOF

# Copiar y ajustar puerto para cada nodo
for port in 7001 7002 7003 7004 7005; do
    sed "s/7000/$port/g" cluster/7000/valkey.conf > cluster/$port/valkey.conf
done

Iniciar nodos

# Iniciar cada nodo
for port in 7000 7001 7002 7003 7004 7005; do
    cd cluster/$port && valkey-server valkey.conf &
    cd ../..
done

Crear el cluster

valkey-cli --cluster create \
    127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
    127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
    --cluster-replicas 1

Docker Compose

# docker-compose.yml
services:
  node1:
    image: valkey/valkey:latest
    ports:
      - "7000:7000"
      - "17000:17000"
    command: valkey-server --port 7000 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    volumes:
      - ./data/7000:/data

  node2:
    image: valkey/valkey:latest
    ports:
      - "7001:7001"
      - "17001:17001"
    command: valkey-server --port 7001 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    volumes:
      - ./data/7001:/data

  node3:
    image: valkey/valkey:latest
    ports:
      - "7002:7002"
      - "17002:17002"
    command: valkey-server --port 7002 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    volumes:
      - ./data/7002:/data

Comandos de cluster

# Conectar a un nodo
valkey-cli -c -p 7000

# Info del cluster
CLUSTER INFO

# Nodos del cluster
CLUSTER NODES

# Slots asignados
CLUSTER SLOTS

# Qué nodo tiene una clave
CLUSTER KEYSLOT mi_clave
# (integer) 12539

# Contar claves en un slot
CLUSTER COUNTKEYSINSLOT 12539

Operaciones con claves

# El cliente redirige automáticamente con -c
valkey-cli -c -p 7000

SET usuario:1 "Juan"
# -> Redirected to slot [12182] located at 127.0.0.1:7002

GET usuario:1
# "Juan"

Hash Tags para colocación

# Claves con mismo hash tag van al mismo slot
SET {user:1}:perfil "datos"
SET {user:1}:sesiones "sesiones"
SET {user:1}:preferencias "prefs"

# Todas en el mismo slot (calculado sobre "user:1")
CLUSTER KEYSLOT {user:1}:perfil
CLUSTER KEYSLOT {user:1}:sesiones
# Mismo resultado

Gestión del cluster

Añadir nodo

# Añadir como master vacío
valkey-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

# Añadir como réplica
valkey-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 \
    --cluster-slave --cluster-master-id <node-id>

Rebalancear slots

# Redistribuir slots equitativamente
valkey-cli --cluster rebalance 127.0.0.1:7000

# Mover slots específicos
valkey-cli --cluster reshard 127.0.0.1:7000 \
    --cluster-from <source-node-id> \
    --cluster-to <target-node-id> \
    --cluster-slots 1000

Eliminar nodo

# Primero mover sus slots
valkey-cli --cluster reshard 127.0.0.1:7000

# Luego eliminar
valkey-cli --cluster del-node 127.0.0.1:7000 <node-id>

Failover

# Failover manual (ejecutar en réplica)
CLUSTER FAILOVER

# Forzar failover
CLUSTER FAILOVER FORCE

# Ver estado
CLUSTER INFO
# cluster_state:ok

Conexión desde aplicaciones

Python

from valkey.cluster import ValkeyCluster

rc = ValkeyCluster(
    host='localhost',
    port=7000,
    decode_responses=True
)

rc.set('clave', 'valor')
valor = rc.get('clave')

# Operaciones multi-key (mismo slot)
rc.mset({'{user:1}:a': '1', '{user:1}:b': '2'})

Node.js

import { createCluster } from 'valkey';

const cluster = createCluster({
    rootNodes: [
        { url: 'valkey://localhost:7000' },
        { url: 'valkey://localhost:7001' },
        { url: 'valkey://localhost:7002' }
    ]
});

await cluster.connect();
await cluster.set('clave', 'valor');
const valor = await cluster.get('clave');

Limitaciones del cluster

# Esto falla (diferentes slots)
MGET usuario:1 usuario:2 usuario:3

# Esto funciona (mismo slot con hash tag)
MGET {user}:1 {user}:2 {user}:3

Monitoreo

# Estado general
valkey-cli --cluster check 127.0.0.1:7000

# Info de cada nodo
valkey-cli --cluster info 127.0.0.1:7000

# Script de monitoreo
#!/bin/bash
for port in 7000 7001 7002; do
    echo "=== Nodo $port ==="
    valkey-cli -p $port CLUSTER INFO | grep -E "(state|slots|size)"
done

Ejercicios

  1. Crea un cluster de 6 nodos (3 masters + 3 réplicas)
  2. Implementa hash tags para agrupar datos de usuario
  3. Simula la caída de un master y verifica el failover

Resumen