Clustering and client libraries in applications

Hash slots, slot-aware clients, multi-key limits and hash tags, resharding, connection pooling, retries and idempotency.

Slots and the routing model

redis-cli --cluster create 10.0.0.1:6379 10.0.0.2:6379 10.0.0.3:6379 \
  10.0.0.4:6379 10.0.0.5:6379 10.0.0.6:6379 --cluster-replicas 1

redis-cli -c -p 6379 CLUSTER INFO
redis-cli -c -p 6379 CLUSTER SHARDS
redis-cli -c -p 6379 CLUSTER KEYSLOT user:42
redis-cli -c -p 6379 CLUSTER COUNTKEYSINSLOT 5460

# reshard: move 100 slots to another node, interactively
redis-cli --cluster reshard 10.0.0.1:6379

# rebalance automatically, and check the cluster afterwards
redis-cli --cluster rebalance 10.0.0.1:6379 --cluster-use-empty-masters
redis-cli --cluster check 10.0.0.1:6379
  • There are 16384 slots. A key routes to CRC16(key) mod 16384, and the client must send the command to the node owning that slot.
  • MOVED means the slot lives elsewhere permanently and the client must update its map; ASK means it moved temporarily during a migration and the client should send the command to the named node once.
  • A client that does not handle MOVED and ASK is not cluster-capable. Silent misrouting produces CROSSSLOT errors and lost writes.
  • Multi-key commands work only when all keys hash to the same slot - which is what hash tags provide: {user:42}:profile and {user:42}:cart share a slot.
⚠️
A single hash tag used across the whole application pins every key to one slot, turning a cluster into a single node with extra hops. Tag by the entity you actually need to operate on atomically, and only for those keys.

Client configuration

from redis.cluster import RedisCluster, ClusterNode
from redis.backoff import ExponentialBackoff
from redis.retry import Retry

client = RedisCluster(
    startup_nodes=[
        ClusterNode("10.0.0.1", 6379),
        ClusterNode("10.0.0.2", 6379),
    ],
    decode_responses=True,
    max_connections=50,                 # per node
    socket_timeout=1.0,
    socket_connect_timeout=1.0,
    retry=Retry(ExponentialBackoff(cap=0.5, base=0.05), retries=3),
    retry_on_error=[ConnectionError, TimeoutError],
)

# a multi-key operation needs a shared hash tag
with client.pipeline() as pipe:
    pipe.hset("{user:42}:profile", "name", "Ada")
    pipe.hset("{user:42}:stats", "books", 12)
    pipe.execute()          # same slot, so it succeeds

# this one fails with CROSSSLOT
client.mget("user:42", "user:43")
SettingEffectRecommendation
socket_timeoutFails fast on a slow nodeSet it below your request timeout, or a timeout cascades
max_connectionsPool per nodeSize to application threads divided by nodes
retry_on_errorRetries connection and timeout errorsOnly for idempotent commands
health_check_intervalReconnects idle connectionsBelow the server's timeout, or use it to detect a dead node
decode_responsesReturns str instead of bytesConvenient; costs an encode on writes
  • Retrying a command that is not idempotent can double a counter increment or a queue push. Retry reads freely, and make writes idempotent before enabling a retry policy.
  • Cluster-aware clients refresh the slot map on MOVED, but a full topology change can take a few seconds - expect a brief period of errors during a reshard.
  • Pipelines in cluster mode are per node. A client library that hides this still needs all keys in a pipeline to share a slot.
  • Test the failover path: kill a primary and confirm the application recovers without a restart.

FAQ

Do I need a cluster?
Only when one instance cannot hold the dataset or serve the write throughput you need. A single node with a replica and good monitoring handles a surprising amount of traffic, and cluster mode adds slot routing, multi-key restrictions and resharding operational work.
How do I migrate to a cluster without downtime?
Add a prefix and a hash tag scheme first, deploy clients that read and write both keys so the new format fills in, backfill the old data, verify, then cut over and delete the old keys. The migration is a schema change, so treat it like one.

Replication, Sentinel and high availability Performance, pipelining and monitoring

Last refreshed 2026-09-18.