Redis 挂了,缓存雪崩、Session 丢失、排行榜空白——这不是假设,是每个用 Redis 的团队迟早会遇到的事。单节点 Redis 是单点故障的代名词。问题是:上高可用该选 Sentinel 还是 Cluster?本文从真实业务场景出发,给你一套可落地的选型方案。
痛点:单节点 Redis 的三大致命风险
- 进程崩溃 = 服务不可用:Redis 是单线程模型,一旦 OOM 被 kill 或者主机宕机,所有依赖 Redis 的服务瞬间瘫痪。
- 数据丢失:即使开了 RDB/AOF 持久化,故障恢复期间仍有数据窗口丢失,且恢复耗时不可控。
- 容量天花板:单节点内存上限受物理机限制,当数据量超过 64GB,性能开始劣化,大 key 扫描、fork 快照都会卡顿。
线上出过一个典型事故:某电商大促期间,唯一的 Redis 实例因 maxmemory 配置不当触发 OOM,被 Linux OOM Killer 直接杀掉,导致商品缓存全部失效,数据库瞬间被打爆,故障持续 12 分钟。
方案:两种高可用架构对比
| 维度 | Sentinel(哨兵模式) | Cluster(集群模式) |
|---|---|---|
| 核心能力 | 自动故障转移 + 读写分离 | 数据分片 + 自动故障转移 |
| 数据分布 | 全量数据在每个节点 | 16384 个 slot 分散到多节点 |
| 最大容量 | 受单节点内存限制 | 理论无上限(横向扩展) |
| 客户端复杂度 | 低,标准客户端即可 | 中等,需要支持 MOVED/ASK 重定向 |
| 适用场景 | 数据量 < 32GB,读多写少 | 数据量大、吞吐要求高 |
| 运维复杂度 | 低 | 中高(扩缩容需迁移 slot) |
一句话结论:数据装得下一台机器选 Sentinel,装不下或者需要线性扩展选 Cluster。
实操步骤
场景一:用 Sentinel 搭建 1 主 2 从 + 3 哨兵
架构: 1 个 Master + 2 个 Replica + 3 个 Sentinel 进程(奇数保证投票选主)。
Step 1:启动主从复制
# Master (10.0.1.1:6379) — redis.conf
bind 0.0.0.0
port 6379
requirepass "YourStrongPass123"
masterauth "YourStrongPass123"
# Replica (10.0.1.2:6379 / 10.0.1.3:6379) — redis.conf
bind 0.0.0.0
port 6379
requirepass "YourStrongPass123"
masterauth "YourStrongPass123"
replicaof 10.0.1.1 6379
Step 2:配置 Sentinel
三台机器各部署一个 Sentinel,配置相同:
# sentinel.conf
port 26379
sentinel monitor mymaster 10.0.1.1 6379 2
sentinel auth-pass mymaster YourStrongPass123
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 30000
sentinel parallel-syncs mymaster 1
关键参数解释:
- 2 — quorum 值,至少 2 个 Sentinel 同意才触发故障转移
- down-after-milliseconds 5000 — 5 秒无响应判定主观下线
- parallel-syncs 1 — 故障转移时同时同步的从节点数,设为 1 减少带宽冲击
Step 3:启动并验证
# 启动 Sentinel
redis-sentinel /etc/redis/sentinel.conf
# 查看 Sentinel 状态
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
场景二:用 Cluster 搭建 3 主 3 从
当数据量超过单机内存,或者需要超过 10 万 QPS 的写吞吐,上 Cluster:
# 6 个节点(10.0.1.1~10.0.1.6),每个节点 redis.conf 加上:
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
# 启动所有节点后,一条命令创建集群:
redis-cli --cluster create \
10.0.1.1:6379 10.0.1.2:6379 10.0.1.3:6379 \
10.0.1.4:6379 10.0.1.5:6379 10.0.1.6:6379 \
--cluster-replicas 1 -a YourStrongPass123
# 验证集群状态
redis-cli -c -a YourStrongPass123 cluster info
redis-cli -c -a YourStrongPass123 cluster nodes
场景三:应用端连接配置(Python 示例)
# Sentinel 模式连接
from redis.sentinel import Sentinel
sentinel = Sentinel(
[('10.0.1.1', 26379), ('10.0.1.2', 26379), ('10.0.1.3', 26379)],
socket_timeout=0.5,
password='YourStrongPass123'
)
master = sentinel.master_for('mymaster', password='YourStrongPass123')
slave = sentinel.slave_for('mymaster', password='YourStrongPass123')
master.set('key', 'value') # 写走 Master
print(slave.get('key')) # 读走 Replica
# Cluster 模式连接
from redis.cluster import RedisCluster
rc = RedisCluster(
startup_nodes=[{"host": "10.0.1.1", "port": 6379}],
password='YourStrongPass123',
decode_responses=True
)
rc.set('key', 'value')
print(rc.get('key'))
3 个常见坑
坑 1:Sentinel 脑裂导致数据丢失
现象: 网络分区时,旧 Master 还在接受写入,Sentinel 已经选出新 Master,分区恢复后旧 Master 降为 Replica,期间写入的数据全部丢失。
解法: 在 Master 的 redis.conf 中加:
min-replicas-to-write 1
min-replicas-max-lag 10
含义:如果没有至少 1 个 Replica 在 10 秒内同步过数据,Master 拒绝写入。这样分区后的孤立 Master 会自动拒绝写请求,避免脑裂丢数据。
坑 2:Cluster 模式下 multi-key 操作报错
现象: MGET key1 key2 key3 直接报 CROSSSLOT Keys in request don't hash to the same slot。
解法: 使用 Hash Tag 强制相关 key 落到同一个 slot:
# 用 {} 包裹的部分决定 slot 分配
SET {user:1001}.name "张三"
SET {user:1001}.age "30"
MGET {user:1001}.name {user:1001}.age # 正常执行
坑 3:Cluster 扩容后 slot 分布不均
现象: 新增节点后,部分节点 slot 数为 0,请求全压在旧节点上。
解法: 扩容后必须手动 rebalance:
# 添加新节点
redis-cli --cluster add-node 10.0.1.7:6379 10.0.1.1:6379 -a YourStrongPass123
# 重新平衡 slot
redis-cli --cluster rebalance 10.0.1.1:6379 \
--cluster-use-empty-masters -a YourStrongPass123
# 确认分布
redis-cli --cluster info 10.0.1.1:6379 -a YourStrongPass123
总结
- 数据量 < 32GB + 读多写少 → Sentinel(1 主 2 从 + 3 哨兵),运维简单,成本低
- 数据量大或写吞吐要求高 → Cluster(至少 3 主 3 从),支持线性扩展
- 防脑裂必须配
min-replicas-to-write,Cluster 扩容后必须rebalance - 不管哪种方案,监控是底线:Sentinel 要监控
sentinel_masters_down,Cluster 要监控cluster_state和 slot 覆盖率
选对架构只是第一步,后续还要关注持久化策略(RDB + AOF 混合)、内存淘汰策略(allkeys-lru vs volatile-ttl)、以及大 key 治理。这些留给下一篇。