Overview
A single Redis instance is a single point of failure. Sentinel provides automatic failover for a primary-replica setup, while Cluster shards data across multiple nodes for horizontal scaling. This tutorial explains when to use each and how to configure them.
Sentinel vs Cluster
| Aspect | Sentinel | Cluster |
|---|---|---|
| Purpose | High availability | High availability + horizontal scaling |
| Data distribution | All data on every node | Sharded across 16,384 hash slots |
| Max dataset | Limited by single-node RAM | Scales with node count |
| Complexity | Moderate | Higher |
| Multi-key operations | Always supported | Only within the same hash slot |
| Minimum nodes | 3 Sentinels + 1 primary + 1 replica | 6 (3 primaries + 3 replicas) |
Part 1: Redis Sentinel
Architecture
Sentinel is a separate process that monitors Redis instances. A quorum of Sentinels must agree that the primary is down before promoting a replica.
┌────────────┐
│ Sentinel 1 │
└─────┬──────┘
│ monitors
┌───────────┼───────────┐
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────────┐
│Primary│──▶│Replica│ │ Sentinel 2│
└──────┘ └──────┘ └──────────┘
▲
│
┌──────┐
│Replica│
└──────┘
Primary Configuration
# redis-primary.conf
port 6379
bind 0.0.0.0
requirepass yourpassword
masterauth yourpassword
appendonly yes
save 900 1
Replica Configuration
# redis-replica.conf
port 6379
bind 0.0.0.0
requirepass yourpassword
masterauth yourpassword
replicaof 10.0.0.1 6379
replica-read-only yes
Sentinel Configuration
# sentinel.conf
port 26379
sentinel monitor mymaster 10.0.0.1 6379 2
sentinel auth-pass mymaster yourpassword
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
| Directive | Meaning |
|---|---|
sentinel monitor | Name, host, port, and quorum for the primary |
down-after-milliseconds | Time before a node is considered down |
failover-timeout | Minimum time between failover attempts |
parallel-syncs | Replicas resyncing simultaneously after failover |
Connecting Through Sentinel
from redis.sentinel import Sentinel
sentinel = Sentinel(
[('sentinel1', 26379), ('sentinel2', 26379), ('sentinel3', 26379)],
socket_timeout=0.5,
)
master = sentinel.master_for('mymaster', password='yourpassword')
replica = sentinel.slave_for('mymaster', password='yourpassword')
master.set('key', 'value')
print(replica.get('key'))
The client asks Sentinel for the current primary address and reconnects automatically after a failover.
Part 2: Redis Cluster
Hash Slots
Cluster divides the keyspace into 16,384 slots. Each key is mapped with CRC16(key) mod 16384. Every primary owns a range of slots.
Creating a Cluster with Docker
# Create the network
docker network create redis-cluster
# Start six nodes
for port in 7000 7001 7002 7003 7004 7005; do
mkdir -p ./node-$port
docker run -d --name redis-$port --net redis-cluster \
-v $(pwd)/node-$port:/data \
redis:7-alpine \
redis-server --port $port \
--cluster-enabled yes \
--cluster-config-file nodes.conf \
--cluster-node-timeout 5000 \
--appendonly yes \
--protected-mode no
done
# Get container IPs and create the cluster
docker exec -it redis-7000 redis-cli --cluster create \
$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-7000):7000 \
$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-7001):7001 \
$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-7002):7002 \
$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-7003):7003 \
$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-7004):7004 \
$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-7005):7005 \
--cluster-replicas 1
Cluster Commands
# Check cluster state
redis-cli -c -p 7000 cluster info
redis-cli -c -p 7000 cluster nodes
# Which node holds a key
redis-cli -c -p 7000 cluster keyslot user:1001
# Reshard slots
redis-cli --cluster reshard 172.20.0.2:7000
# Add a new node
redis-cli --cluster add-node 172.20.0.10:7006 172.20.0.2:7000
# Rebalance slots across nodes
redis-cli --cluster rebalance 172.20.0.2:7000
Cluster-Aware Clients
from redis.cluster import RedisCluster, ClusterNode
nodes = [
ClusterNode('10.0.0.1', 7000),
ClusterNode('10.0.0.2', 7000),
ClusterNode('10.0.0.3', 7000),
]
rc = RedisCluster(startup_nodes=nodes, decode_responses=True)
rc.set('user:1001', 'Alice')
print(rc.get('user:1001'))
Hash Tags for Multi-Key Operations
Multi-key operations require all keys to be in the same slot. Use hash tags to force this:
# Different slots — MGET fails in cluster mode
MGET user:1001:name user:1002:name
# Same slot because the tag between {} is hashed
MGET user:{1001}:name user:{1001}:email
Client-Side Considerations
| Feature | Sentinel | Cluster |
|---|---|---|
| Pipelines across keys | Supported | Only same-slot keys |
| Transactions (MULTI/EXEC) | Supported | Only same-slot keys |
| Lua scripts | Supported | Only same-slot keys |
| Pub/Sub | Cluster-wide | Broadcast across nodes |
| Failover | Sentinel promotes replica | Cluster promotes replica automatically |
Operational Best Practices
- Run at least three Sentinel instances across separate failure domains.
- Set
min-replicas-to-write 1andmin-replicas-max-lag 10to avoid writing to an isolated primary. - Use an odd number of primaries in a Cluster (3, 5) to maintain quorum.
- Monitor replication lag; alert when it exceeds your tolerance.
- Enable AOF persistence for durability in addition to RDB snapshots.
- Test failover regularly in staging. An untested failover path is not a reliable one.
Common Pitfalls
| Pitfall | Result | Fix |
|---|---|---|
| Even number of Sentinels | Split-brain during quorum voting | Always use an odd count |
| All Sentinels on one host | Host failure takes down monitoring | Distribute across zones |
| Cluster without replicas | Data loss on primary failure | Run at least one replica per primary |
| Keys not hash-tagged | Multi-key operations fail | Use {tag} in key names |
