Redis Sentinel vs Cluster Failover
This page decides whether a Redis deployment should recover from a lost primary using an external Sentinel quorum or the gossip-driven failover built into Redis Cluster — and how to run each so a node loss is a two-second blip rather than a split-brain incident.
Automatic failover is the mechanism that turns a dead primary into a promoted replica without a human in the loop, and the two supported ways to do it in Redis 7.x are not interchangeable. Sentinel bolts high availability onto a classic single-primary-with-replicas layout: a separate fleet of monitoring processes watches the data nodes, agrees that one has died, and promotes a replica. Redis Cluster folds failover into the data plane itself: every node gossips health over a bus, and a replica whose primary is declared failed promotes itself by winning a vote among the surviving primaries. The two models differ in what fails over, how clients find the new primary, and how much operational surface you take on. The topology baseline they build on is established in Redis High Availability & Failover Automation; this page is where you actually pick between them.
Architectural Trade-offs
Both models deliver the same headline guarantee — a replica takes over automatically when a primary dies — but they reach it through completely different machinery, and that machinery is what you operate at 3 a.m. Sentinel keeps monitoring outside the data path; Cluster embeds it. The columns below are the axes that decide which set of costs your workload can absorb.
| Approach | Failover mechanism | Client awareness | Data/sharding model | Operational complexity |
|---|---|---|---|---|
| Redis Sentinel | External quorum of Sentinel processes votes a replica into primacy after down-after-milliseconds |
Client asks Sentinels for the current primary via SENTINEL get-master-addr-by-name, then connects directly |
Single primary holding the whole keyspace, plus N read replicas | Low–Medium — one extra process class, but a separate fleet to size and monitor |
| Redis Cluster | In-band gossip bus; a replica self-promotes by winning a vote among surviving primaries after cluster-node-timeout |
Client follows MOVED/ASK redirects and refreshes its slot map on topology change |
Keyspace sharded across 16,384 hash slots over many primaries | Medium–High — every node is HA-aware, and sharding constrains multi-key commands |
| Sentinel + client-side sharding | Sentinel per shard-group; failover is per primary | Client resolves each shard's primary independently through its Sentinel set | Application partitions keys; each partition is a Sentinel-guarded primary | High — you own the sharding logic Cluster gives you for free |
The distinction that trips teams up is in the first two columns. Sentinel's failover is a decision made about the data nodes by processes that hold no data; the client must consult that external authority to learn who the primary is now. Cluster's failover is a decision the data nodes make among themselves, and the client learns about it reactively, by being redirected the next time it addresses a moved slot. Neither is strictly better — the right one falls out of whether your dataset fits one primary and which model your client library speaks natively.
Approach A — Redis Sentinel
Sentinel is a distributed monitoring and failover coordinator that runs as its own process — typically three or five instances spread across failure domains, deliberately more than the two you might guess, so a partition can never leave the survivors without a majority. Each Sentinel PINGs the primary and its replicas on an interval. When a Sentinel stops getting replies from the primary for longer than down-after-milliseconds, it flags the primary as subjectively down (SDOWN). That flag alone changes nothing: Sentinel then asks the other Sentinels whether they agree, and only when a configured quorum of them concur is the primary marked objectively down (ODOWN). Objective-down is the trigger that authorizes a failover.
Failover itself is a two-vote process people often conflate. First, the Sentinels elect a leader among themselves — this uses a Raft-style term and requires a strict majority of the total Sentinel count, independent of the quorum value. The elected leader then selects the best replica (highest priority, most replication data, lowest run-id as a tiebreak), issues REPLICAOF NO ONE to promote it, and reconfigures the remaining replicas to follow the new primary. The old primary, when it returns, is demoted to a replica of the winner. Because promotion is decoupled from the client, applications never talk to Sentinels on the hot path — they query them only to discover the primary's address:
import redis.asyncio as redis
from redis.asyncio.sentinel import Sentinel
# Point the client at the Sentinel quorum, NOT at the data nodes directly.
# One unreachable Sentinel must not break discovery, hence a short timeout.
sentinel = Sentinel(
[("sentinel-a", 26379), ("sentinel-b", 26379), ("sentinel-c", 26379)],
socket_timeout=0.5,
sentinel_kwargs={"password": "sentinel-secret"}, # auth to the Sentinels
)
def get_writer() -> redis.Redis:
# master_for issues SENTINEL get-master-addr-by-name under the hood and
# returns a client bound to the *current* primary. After a failover the
# next command transparently reconnects to the newly promoted node.
return sentinel.master_for(
"mymaster",
password="data-node-secret", # auth to the data nodes
socket_timeout=0.5,
decode_responses=True,
)
def get_reader() -> redis.Redis:
# slave_for load-balances reads across the healthy replicas of mymaster,
# keeping read traffic off the primary.
return sentinel.slave_for("mymaster", decode_responses=True)
async def write_session(user_id: str, token: str) -> None:
writer = get_writer()
# Keep a safety-net TTL on cached state so a stale read after a failover
# self-heals rather than persisting until the next explicit write.
await writer.set(f"session:{user_id}", token, ex=900)
Sentinel is the right default when the entire working set fits comfortably in one primary's memory and you want availability without giving up the operational simplicity of a single, un-sharded keyspace. Every multi-key operation, MULTI/EXEC transaction, and Lua script runs against one node with no cross-slot restriction — a real advantage for code that touches many related keys at once. The cost is that the primary is a throughput ceiling: reads scale out across replicas, but every write funnels through one node. Pair session and cache state with a conservative TTL so the brief window of ambiguity during a failover cannot leave keys stale indefinitely.
Approach B — Redis Cluster Native Failover
Redis Cluster removes the external coordinator entirely by making every data node a participant in a peer-to-peer health protocol. Nodes exchange compact gossip messages over a dedicated cluster bus (the client port plus 10000) carrying heartbeats, known-node lists, and failure reports. When a primary stops responding to a node's pings for longer than cluster-node-timeout, that node marks it PFAIL (possible failure) and gossips the suspicion. Once a majority of primaries have independently reported PFAIL for the same node, it is promoted to FAIL and broadcast cluster-wide — the same majority principle Sentinel enforces, but built into the data plane rather than a separate fleet.
Recovery is then driven by the failed primary's own replicas rather than an outside authority. Each eligible replica waits a short, rank-ordered delay (the replica with the freshest replication offset waits least, reducing data loss) and then requests votes from the surviving primaries via a FAILOVER_AUTH_REQUEST. A primary grants at most one vote per configuration epoch, so exactly one replica can win. The winner claims its dead primary's hash slots, bumps the configuration epoch, and gossips the new slot ownership; the rest of the Redis cluster updates its slot map accordingly. Clients are not notified — they discover the change lazily. The first command a client sends to a slot the promoted replica now owns returns a MOVED reply pointing at the new node, and a well-behaved client updates its slot cache and retries. The same redirection machinery is documented in MOVED redirection. redis-py's async cluster client handles all of this internally:
import redis.asyncio as redis
from redis.asyncio.cluster import RedisCluster, ClusterNode
from redis.backoff import ExponentialBackoff
from redis.retry import Retry
# The client bootstraps its slot map from any reachable node, then routes
# each key to the primary that owns its slot. On a MOVED/ASK reply it
# refreshes the map and retries — so a native failover is transparent.
cluster = RedisCluster(
startup_nodes=[
ClusterNode("redis-1", 6379),
ClusterNode("redis-2", 6379),
ClusterNode("redis-3", 6379),
],
require_full_coverage=True, # refuse to serve if any slot range is unowned
read_from_replicas=True, # spread reads; writes still go to the primary
retry=Retry(ExponentialBackoff(cap=1.0, base=0.05), retries=5),
socket_timeout=1.0,
decode_responses=True,
)
async def cache_product(product_id: str, payload: str) -> None:
# Hash-tag co-locates related keys in ONE slot so a multi-key op stays on
# a single node even as slots move during a failover or migration.
await cluster.set(f"product:{{{product_id}}}:body", payload, ex=600)
await cluster.set(f"product:{{{product_id}}}:meta", "v3", ex=600)
Cluster is the right choice when the keyspace or write throughput outgrows a single primary and horizontal sharding is a requirement rather than a nicety. Failover is per shard: losing one primary promotes one replica while the other shards keep serving, so the blast radius of a node death is a fraction of the keyspace instead of all of it. The price is the sharding contract. Multi-key commands must keep every key in one slot via hash tags, cross-slot transactions are rejected outright, and the client must be a genuine cluster client that maintains a slot map and honors redirects — a thin connection wrapper that ignores MOVED will thrash. That client requirement, more than anything else, is what pushes teams with a limited driver back toward Sentinel.
When to Choose Which
Resolve the decision against concrete deployment facts, not familiarity. The flow below encodes the primary branch; the numbered criteria refine it.
- Does the dataset fit one primary? If the working set and write rate sit comfortably inside a single node's memory and CPU, Sentinel gives you availability without the sharding tax — un-sharded multi-key commands, transactions, and Lua all just work. The moment you need horizontal write scale or exceed one node's memory, native Redis Cluster failover is the model that comes with the sharding you already require.
- Does your client library support the model? Sentinel discovery and cluster slot-routing are distinct client capabilities, and not every driver, ORM, or framework integration speaks both. A client that only understands a single endpoint can be paired with Sentinel behind a discovery step, but Redis Cluster demands a true cluster client that maintains a slot map and follows
MOVED/ASK. Confirm your language's client — and any connection pooler between it and Redis — supports the target model before committing. - What operational burden can you carry? Sentinel adds one more process class to run, patch, and monitor, but leaves the data topology flat and easy to reason about. Cluster folds HA into the data nodes yet makes every node HA-aware, constrains multi-key access, and turns resharding into a first-class operation. Weigh the standing cost of a Sentinel fleet against the standing complexity of a sharded cluster; the sibling guidance in Connection Pooling and Client Resilience covers how each model interacts with pool sizing under load.
For most single-primary services the answer is Sentinel; for anything that has genuinely outgrown one node, native Cluster failover is the model that scales the data and the availability together. The full worked comparison, with capacity thresholds, lives in Sentinel vs Cluster: Which Failover Model to Choose.
Failure Modes and Diagnostics
Three failure modes account for most failover incidents. Each has a fast diagnosis before you commit to a fix.
Split-brain on a network partition. A partition isolates the primary from the majority. The survivors promote a replica, but the old primary — still reachable by some clients on its side of the partition — keeps accepting writes. Now two nodes believe they are primary, and every write to the minority side is doomed to be discarded when the partition heals and the old primary demotes itself. Diagnose by looking for two nodes claiming the primary role and divergent replication offsets:
# Cluster: look for more than one node flagged "master" for the same slots,
# or a node still "master" that the majority already flagged fail.
redis-cli -c CLUSTER NODES | grep master
# Sentinel: a healthy view reports exactly one primary and agreeing sentinels.
redis-cli -p 26379 SENTINEL master mymaster | grep -A1 -E "num-slaves|num-other-sentinels|flags"
The fix is prevention, not cure: on the data nodes set min-replicas-to-write 1 and min-replicas-max-lag 10 so a primary that cannot see at least one sufficiently caught-up replica refuses writes, collapsing the minority side's acceptance window. For Cluster, keep cluster-node-timeout long enough that a transient blip is not mistaken for death.
Quorum set too low. If the Sentinel quorum is configured below a strict majority of the Sentinel count, a minority of Sentinels caught on the wrong side of a partition can declare the primary objectively down and start a failover the rest of the fleet would have vetoed — manufacturing exactly the split-brain above. Diagnose by comparing the configured quorum against the number of Sentinels actually monitoring the primary:
# quorum should be floor(N/2)+1 where N = num-other-sentinels + 1.
redis-cli -p 26379 SENTINEL master mymaster | grep -A1 -E "quorum|num-other-sentinels"
If quorum is 2 while only 3 Sentinels exist, the value is correct; if quorum is 1, any single Sentinel can trigger a failover — raise it to a real majority. Note that even a correct quorum only gates the ODOWN decision; the actual promotion still requires a leader elected by a majority of the total, which is the backstop that makes a sane quorum safe.
Failover thrash (flapping). An overly aggressive down-after-milliseconds or cluster-node-timeout turns ordinary latency spikes — a slow BGSAVE, a GC pause, brief packet loss — into repeated false failovers, each one a promotion, a client-side redirect storm, and a full re-sync that further loads the nodes. Diagnose by watching the role and epoch change more often than real outages could explain:
# Cluster: a rapidly climbing config epoch means repeated promotions.
redis-cli CLUSTER INFO | grep -E "cluster_state|cluster_current_epoch|cluster_stats_messages"
# Any node: role changes logged far more often than nodes actually die.
redis-cli INFO replication | grep -E "role|master_link_status|slave_repl_offset"
The fix is to widen the failure-detection window until it comfortably clears your worst legitimate pause, and to attack the root cause — replace blocking commands, offload KEYS to SCAN, and cap value sizes so no single operation stalls the event loop long enough to look like death.
Verification
Confirm the chosen model is genuinely healthy against a live deployment before trusting it to fail over under load.
For Sentinel, verify every Sentinel agrees on one primary, sees the expected replica count, and reports a quorum that is a true majority:
redis-cli -p 26379 SENTINEL masters
# Inspect one primary in detail: flags should read "master" (never "s_down"
# or "o_down" in steady state), num-slaves matches your topology, and
# num-other-sentinels + 1 forms a majority over the quorum value.
redis-cli -p 26379 SENTINEL master mymaster
For Redis Cluster, confirm the deployment is in the ok state with full slot coverage and no failed nodes lingering in the membership view:
redis-cli CLUSTER INFO
# Expect cluster_state:ok and cluster_slots_assigned:16384. Anything less
# means a slot range is unowned and require_full_coverage will reject writes.
redis-cli -c CLUSTER NODES | grep -c master # one master per shard, no dup
For either model, verify the replication link on the promoted or standing primary is live and the replicas are caught up — a failover that leaves a replica lagging is a data-loss window waiting to open:
redis-cli INFO replication
# On the primary: role:master with connected_slaves >= 1 and each slave line
# showing state=online. On a replica: master_link_status:up and a
# slave_repl_offset that tracks the primary's master_repl_offset closely.
A healthy deployment holds role:master on exactly one node per shard, master_link_status:up on every replica, and a replication offset gap that stays near zero. Treat a persistent offset gap, a flapping master_link_status, or a cluster_state:fail as the same class of signal you would page on, and rehearse an actual failover in a game day rather than assuming the automation works — the model is only as good as the last time you watched it promote a replica for real.
Up one level: Redis High Availability & Failover Automation
Related
- Configuring Redis Sentinel Quorum for Automatic Failover — sizing the Sentinel fleet and quorum so failover is safe, not trigger-happy.
- Sentinel vs Cluster: Which Failover Model to Choose — the worked decision with capacity thresholds.
- Replication and Read Scaling with Redis Replicas — the replica layer both failover models promote from.
- Connection Pooling and Client Resilience — how pools survive a primary swap under each model.