Chapter 21 · Redis Cluster: Hash Slots, Routing, Resharding, and Cluster Availability

16384 Hash Slots, CRC16, Key Distribution, Nodes, Primaries, Replicas, and Cluster Bus

Build the slot-level mental model for Redis Cluster, including CRC16, hash tags, shards, replicas, topology APIs, and the private Cluster bus.

Advanced220–320 minutesslots, CRC16, topology, cluster bus, six-node labRedis Open Source 8.10.1Docker + redis-cli + redis-py 8.1.06-node Cluster + 1 spare nodeDB 0 · AOF everysec · maxmemory 0/noevictionFree/local-firstLast reviewed: September 6, 2026

Learning outcomes

By the end of this lesson, you should be able to:

01

Explain why Redis Cluster partitions the keyspace into exactly 16,384 hash slots rather than hashing keys directly to a permanent node.

02

Calculate and verify slot placement with CRC16 modulo 16,384 and the hash-tag exception.

03

Read CLUSTER INFO, CLUSTER SHARDS, and CLUSTER NODES as different views of one topology.

04

Distinguish client port 6379 from the node-to-node Cluster bus and explain primary/replica shard membership.

05

Create a reproducible six-node Cluster without exposing Cluster ports to the host network.

Reproducible Chapter 21 baseline

Redis Open Source 8.10.1 using redis:8.10.1; seven named containers are defined but the normal cluster starts six nodes (three primaries + three replicas) on private Docker network atlasmart-redis-ch21-net; the seventh node is started only for add/remove exercises; Redis Cluster uses logical database 0 only; AOF everysec; maxmemory 0/noeviction for this bounded lab; TLS is off only because all Cluster client/bus traffic is confined to one private single-host Docker network; default ACL user is disabled; named academy-admin and atlasmart-app users use disposable lab passwords. No Search/JSON/vector/time-series/probabilistic feature is required. All keys use atlasmart:ch21:*.

1. Practical problem: one primary cannot scale every AtlasMart key

AtlasMart now has carts, inventory, sessions, and ranking keys whose combined working set and request rate no longer fit one Redis primary comfortably. Redis Cluster solves this by partitioning key ownership across multiple primaries while retaining replicas for failover. The unit of placement is not “a server” but a hash slot.

A slot is a numbered bucket in the range 0–16383. A primary owns a set of slots; every key maps to exactly one slot; therefore moving slot ownership can move data responsibility without changing the key itself.

2. Exact slot formula: CRC16 modulo 16,384

For an ordinary key Redis Cluster computes the XMODEM CRC16 checksum and keeps 14 effective bits by applying modulo 16,384. The formula is HASH_SLOT = CRC16(key) mod 16384. The important operational consequence is that nodes can be added or removed by transferring slot ranges instead of changing a consistent-hash ring.

Shell · let Redis prove slot placement
docker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 \  redis-cli --user academy-admin CLUSTER KEYSLOT atlasmart:ch21:product:1001docker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 \  redis-cli --user academy-admin CLUSTER KEYSLOT atlasmart:ch21:cart:{customer-42}:lines

3. Hash tags change what gets hashed

If a key contains a valid non-empty {...} substring, only the substring between the first valid brace pair is hashed. That lets related keys intentionally share one slot. It is a locality tool, not a free performance trick: putting every AtlasMart key under one tag would collapse a sharded cluster back into one hot slot.

Key Hashed material Design implication
atlasmart:ch21:cart:{customer-42}:lines customer-42 Can share multi-key operations with same tag
atlasmart:ch21:cart:{customer-42}:meta customer-42 Same slot as lines
atlasmart:ch21:cart:{customer-99}:meta customer-99 Normally different slot
atlasmart:ch21:product:1001 whole key Naturally distributed

4. Node, shard, primary, replica, and Cluster bus

A node is one Redis server participating in the Cluster gossip protocol. A shard is one primary plus the replicas that replicate that primary and serve the same slots. Nodes exchange failure, slot, epoch, and topology information over the Cluster bus, distinct from normal RESP client traffic. In the default TCP layout the bus port is derived from the client port; this lab keeps both private inside Docker.

5. Build the private seven-service lab definition

The normal topology starts only n1–n6. n7 exists in the Compose file but remains stopped until Lesson 4. Use at least about 1 GB of free RAM and 1 GB of free disk for a comfortable single-host exercise; smaller machines can reduce dataset volume because correctness does not depend on a large dataset.

YAML · ch21-compose.yaml
name: atlasmart-redis-ch21x-node: &node  image: redis:8.10.1  restart: "no"  networks: [cluster]  volumes:    - ./users.acl:/usr/local/etc/redis/users.acl:ro  command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]services:  n1:    <<: *node    container_name: atlasmart-redis-ch21-n1    hostname: atlasmart-redis-ch21-n1    command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-announce-hostname","atlasmart-redis-ch21-n1","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]    volumes: ["./users.acl:/usr/local/etc/redis/users.acl:ro","n1:/data"]  n2:    <<: *node    container_name: atlasmart-redis-ch21-n2    hostname: atlasmart-redis-ch21-n2    command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-announce-hostname","atlasmart-redis-ch21-n2","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]    volumes: ["./users.acl:/usr/local/etc/redis/users.acl:ro","n2:/data"]  n3:    <<: *node    container_name: atlasmart-redis-ch21-n3    hostname: atlasmart-redis-ch21-n3    command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-announce-hostname","atlasmart-redis-ch21-n3","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]    volumes: ["./users.acl:/usr/local/etc/redis/users.acl:ro","n3:/data"]  n4:    <<: *node    container_name: atlasmart-redis-ch21-n4    hostname: atlasmart-redis-ch21-n4    command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-announce-hostname","atlasmart-redis-ch21-n4","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]    volumes: ["./users.acl:/usr/local/etc/redis/users.acl:ro","n4:/data"]  n5:    <<: *node    container_name: atlasmart-redis-ch21-n5    hostname: atlasmart-redis-ch21-n5    command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-announce-hostname","atlasmart-redis-ch21-n5","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]    volumes: ["./users.acl:/usr/local/etc/redis/users.acl:ro","n5:/data"]  n6:    <<: *node    container_name: atlasmart-redis-ch21-n6    hostname: atlasmart-redis-ch21-n6    command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-announce-hostname","atlasmart-redis-ch21-n6","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]    volumes: ["./users.acl:/usr/local/etc/redis/users.acl:ro","n6:/data"]  n7:    <<: *node    container_name: atlasmart-redis-ch21-n7    hostname: atlasmart-redis-ch21-n7    command: ["redis-server","--port","6379","--cluster-enabled","yes","--cluster-config-file","nodes.conf","--cluster-node-timeout","5000","--cluster-announce-hostname","atlasmart-redis-ch21-n7","--cluster-preferred-endpoint-type","hostname","--appendonly","yes","--appendfsync","everysec","--save","300","10","--aclfile","/usr/local/etc/redis/users.acl","--masteruser","academy-admin","--masterauth","AtlasMart-Ch21-Admin-Lab-Only-2026","--cluster-slot-stats-enabled","yes"]    volumes: ["./users.acl:/usr/local/etc/redis/users.acl:ro","n7:/data"]networks:  cluster:    name: atlasmart-redis-ch21-netvolumes: {n1: {}, n2: {}, n3: {}, n4: {}, n5: {}, n6: {}, n7: {}}
Text · users.acl
user default offuser academy-admin on >AtlasMart-Ch21-Admin-Lab-Only-2026 ~* &* +@alluser atlasmart-app on >AtlasMart-Ch21-App-Lab-Only-2026 ~atlasmart:ch21:* &* +@read +@write +@connection +cluster|shards +cluster|slots +cluster|keyslot

6. Start six nodes and create three shards

Create the Docker network and six processes first, then use the pinned redis-cli inside n1 to allocate all 16,384 slots across three primaries and assign one replica to each primary. The order passed to --cluster create makes n1–n3 the initial primary candidates; always verify the resulting replica pairing rather than assuming it.

Shell · create the initial Cluster
docker compose -f ch21-compose.yaml up -d n1 n2 n3 n4 n5 n6docker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 \  redis-cli --user academy-admin --cluster create \  atlasmart-redis-ch21-n1:6379 atlasmart-redis-ch21-n2:6379 atlasmart-redis-ch21-n3:6379 \  atlasmart-redis-ch21-n4:6379 atlasmart-redis-ch21-n5:6379 atlasmart-redis-ch21-n6:6379 \  --cluster-replicas 1 --cluster-yes

7. Observe three complementary topology views

CLUSTER INFO answers whether the local node considers the cluster operational and whether all slots are assigned/healthy. CLUSTER SHARDS is the preferred modern client topology API since Redis 7. CLUSTER NODES exposes node IDs, flags, config epochs, link state, bus endpoint, slot ranges, and migration markers. CLUSTER SLOTS remains available but has been deprecated since Redis 7.

Shell · inspect topology and coverage
docker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 redis-cli --user academy-admin CLUSTER INFOdocker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 redis-cli --user academy-admin CLUSTER SHARDSdocker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 redis-cli --user academy-admin CLUSTER NODES

8. Expected evidence and its limits

A healthy baseline should show cluster_state:ok, cluster_slots_assigned:16384, three primaries serving slots, and three replicas attached to those primaries. That proves current topology/coverage. It does not prove fault-domain independence: all six containers still share one host, Docker daemon, storage device, and power source.

9. Version-aware observability: per-slot statistics

Redis 8.2 introduced CLUSTER SLOT-STATS. This lab enables slot statistics so you can rank slots by key count, CPU, network bytes, and—on current Redis—memory bytes. This is stronger evidence than counting slots per node because a node with 5,000 mostly-cold slots can still be less loaded than one with a single extremely hot slot.

Shell · inspect hot slots on a primary
docker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 \  redis-cli --user academy-admin CLUSTER SLOT-STATS ORDERBY KEY-COUNT LIMIT 10 DESCdocker exec -e REDISCLI_AUTH=AtlasMart-Ch21-Admin-Lab-Only-2026 atlasmart-redis-ch21-n1 \  redis-cli --user academy-admin CLUSTER SLOT-STATS ORDERBY CPU-USEC LIMIT 10 DESC

10. Deliberately wrong model: node count equals zone safety

Six processes on one laptop can teach Cluster algorithms but do not provide six independent failure domains. Production placement must consider hosts, racks/zones, power/network domains, disk, and client reachability. A replica on the same failed host as its primary contributes almost no host-failure protection.

Check your understanding

  1. Why does Redis Cluster use slots between keys and nodes?
  2. What formula maps an ordinary key to a slot?
  3. Why prefer CLUSTER SHARDS in new client/topology code?
  4. Does cluster_state:ok prove zone redundancy?
Review the answers

Slots provide a stable partitioning layer that can be reassigned during scale/failover without changing each key name.

XMODEM CRC16 of the key modulo 16384.

It is the extensible topology API introduced in Redis 7 and replaces deprecated CLUSTER SLOTS.

No. It proves current cluster health from that node’s perspective, not physical failure-domain placement.

11. Production judgment and bridge

Redis Cluster is appropriate when one logical Redis dataset needs horizontal key partitioning and clients can route by slot. It does not provide arbitrary cross-slot transactions or hide network topology. Capacity planning must include per-primary working set, replicas, failover headroom, reshard traffic, AOF/persistence, Cluster bus traffic, and client topology refresh. Lesson 2 turns routing failures into observable MOVED/ASK behavior.

Summary and next step

16384 Hash Slots, CRC16, Key Distribution, Nodes, Primaries, Replicas, and Cluster Bus is now connected to observable Redis behavior, bounded failure cases, and production tradeoffs. Keep the evidence and cleanup state from this lesson; next, continue with MOVED vs ASK Redirections, Cluster-Aware Clients, Topology Refresh, and Retry Behavior.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.