外观
Redis 高可用选型:哨兵、Cluster 与云托管决策矩阵
为什么 Redis 高可用不能只看主从复制
很多团队第一次做 Redis 高可用,都会从“主库加从库”开始:主节点负责写入,从节点负责读或备份,再配合 RDB/AOF 降低数据丢失风险。但主从复制只解决数据冗余,不解决自动故障判定与主节点切换。一旦主库进程退出、机器宕机或网络分区,业务仍需要人工修改连接地址,故障恢复时间往往取决于值班同学是否在线。
Redis 高可用选型的本质,不是比较哪个名词更先进,而是回答四个问题:数据规模是否会超过单节点内存?业务能否接受秒级切换?是否需要分片扩展?团队是否具备持续运维 Redis 的能力?哨兵、Cluster、云托管分别对应三类典型答案。
三类方案的核心差异
Sentinel 哨兵:适合中小容量自动主从切换
哨兵通过一组独立进程监控主节点和从节点,多数哨兵认为主库不可达后,会选举领导者并执行故障转移,把某个从节点提升为新主节点,同时通知客户端更新拓扑。它不做数据分片,所有 key 仍在一个主节点上,适合单节点内存可容纳、主要诉求是高可用的场景。
Redis Cluster:适合大容量与水平扩展
Cluster 将 key 通过 CRC16 哈希映射到 16384 个槽,再由多个主节点分管不同槽。每个主节点通常配置复制副本,某个主节点故障时,其副本可被提升为主节点。它同时解决水平扩展与高可用,但客户端必须支持集群协议,业务也要避免跨槽操作。
云托管 Redis:适合降低运维复杂度
云厂商托管版通常封装了主从复制、自动切换、备份恢复、监控告警、参数管理与弹性扩缩容。部分产品兼容哨兵或 Cluster,部分提供代理地址屏蔽后端拓扑。它的优势是运维成本低、SLA 明确;代价是费用更高,能力受产品规格限制,跨云迁移时还要评估兼容性。
选型决策矩阵:按容量、可用性与团队能力打分
可以用下面的矩阵做初筛:
| 维度 | Sentinel | Redis Cluster | 云托管 |
|---|---|---|---|
| 数据容量 | 受单主节点限制 | 多主分片,水平扩展 | 取决于实例规格 |
| 故障切换 | 哨兵多数派决策 | 主副本自动故障转移 | 平台自动处理 |
| 客户端 | 需支持哨兵或做服务发现 | 必须支持 MOVED/ASK | 常提供统一连接地址 |
| 跨槽事务/Lua | 友好 | 限制明显 | 取决于架构与代理 |
| 运维复杂度 | 中等 | 较高 | 低 |
| 成本 | 机器成本低,人力成本高 | 资源与运维成本都较高 | 包年包月或按量付费 |
| 典型场景 | 缓存、会话、排行榜 | 大缓存、大规模在线业务 | 核心业务、小团队、快速上线 |
一个实用决策规则是:数据量在单节点可接受范围内,优先哨兵;已经出现单节点内存、网络或写入瓶颈,选择 Cluster;如果团队没有专人处理备份、升级、告警和切换演练,即使容量不大,也应认真考虑云托管。
可运行命令:验证哨兵与 Cluster 的关键行为
下面示例使用 Docker Compose 在本机启动 1 个主节点、1 个从节点和 3 个哨兵,便于理解拓扑。生产环境应将节点分散到不同机器、可用区或故障域。
yaml
# docker-compose.yml
# 启动:docker compose up -d
# 进入:docker exec -it redis-master redis-cli
services:
redis-master:
image: redis:7.2
command: redis-server --appendonly yes
ports:
- "6379:6379"
redis-replica:
image: redis:7.2
command: redis-server --replicaof redis-master 6379 --appendonly yes
depends_on:
- redis-master
sentinel-1:
image: redis:7.2
command: >
redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel.conf:/etc/redis/sentinel.conf
depends_on:
- redis-master
- redis-replica
sentinel-2:
image: redis:7.2
command: redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel.conf:/etc/redis/sentinel.conf
depends_on:
- redis-master
sentinel-3:
image: redis:7.2
command: redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel.conf:/etc/redis/sentinel.conf
depends_on:
- redis-masterconf
# sentinel.conf
# monitor 后面依次是:主名称、主地址、主端口、判定客观下线所需哨兵数
sentinel monitor mymaster redis-master 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000启动后写入关键数据结构,并观察复制状态:
bash
# 写入用户会话哈希,适合存储对象字段
redis-cli -p 6379 HSET user:1001 name "alice" vip "true" balance "88"
# 写入商品热度 ZSET,适合排行榜
redis-cli -p 6379 ZADD rank:hot 100 item:A 88 item:B 66 item:C
# 查看主节点复制信息:role 应为 master,connected_slaves 至少为 1
redis-cli -p 6379 INFO replication | grep -E "role|connected_slaves"
# 查看哨兵认定的主节点地址与状态
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -p 26379 SENTINEL replicas mymaster模拟主库故障后,哨兵通常会在 down-after-milliseconds 之后开始判定,并在数秒到数十秒内完成切换:
bash
# 暂停主库,观察从库提升过程
docker compose stop redis-master
# 持续观察哨兵日志,能看到 +sdown、+odown、+failover、+switch-master 等事件
docker compose logs -f sentinel-1
# 切换完成后再次查询主节点地址,返回结果可能变成 redis-replica 的地址
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymasterCluster 的验证思路不同,重点是槽分布与重定向。下面创建一个 6 节点最小测试集群,3 主 3 从:
bash
# 创建 6 个测试节点目录,并分别启动节点
for port in 7001 7002 7003 7004 7005 7006; do
mkdir -p cluster/$port
redis-server --port $port \n --cluster-enabled yes \n --cluster-config-file nodes-$port.conf \n --cluster-node-timeout 5000 \n --appendonly yes \n --daemonize yes
done
# 创建集群:前三个为主节点,后三个通过 --cluster-replicas 1 成为副本
redis-cli --cluster create \
127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 \
127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 \
--cluster-replicas 1
# 查看槽分配与主从关系
redis-cli -p 7001 CLUSTER NODES
redis-cli -p 7001 CLUSTER INFO
# -c 表示允许客户端自动跟随 MOVED/ASK 重定向
redis-cli -c -p 7001 SET user:1001 "alice"
redis-cli -c -p 7001 HSET order:2001 amount 99 status paid
# 查看某个 key 所属槽;多 key 操作必须落在同一槽
redis-cli -p 7001 CLUSTER KEYSLOT user:1001Cluster 中如果要同时操作多个 key,应使用 hash tag 强制它们落在同一槽:
bash
# 大括号内内容参与槽计算,user:1001 的 profile 与 cart 会落到同一槽
redis-cli -c -p 7001 HSET {user:1001}:profile name alice
redis-cli -c -p 7001 HSET {user:1001}:cart item:A 2
# 同槽多 key 操作可以成功
redis-cli -c -p 7001 MGET {user:1001}:profile {user:1001}:cart
# 若 key 不带相同 hash tag,跨槽 MGET、事务或 Lua 通常报 CROSSSLOT 错误持久化与高可用不是一回事
高可用关注服务能否继续提供访问,持久化关注进程重启或数据文件损坏后能否恢复数据。主从复制可以减少单点故障影响,但 Redis 默认采用异步复制,主库在返回客户端写入成功后,并不能保证从库已经收到该写入。因此发生主库宕机时,未复制到从库的数据仍可能丢失。
如果业务更关注少丢数据,应开启 AOF,并根据性能要求选择 appendfsync everysec 或 always,同时配合 RDB 做冷备。若业务更关注可用性,可适当降低同步与故障检测门槛,但必须接受极端情况下的数据丢失。不能把“自动切换”误解为“强一致”。
避坑总结:来自生产环境的具体注意事项
哨兵数量不要只部署 1 个,也不要全部放在同一台机器。 常见现象是哨兵进程与主库一起宕机,或者三个哨兵位于同一网络故障域,误判主观下线。修正方法是至少部署 3 个且奇数个哨兵,分布在不同机器或可用区,并设置合理的
quorum。同时应用客户端必须订阅哨兵或使用支持哨兵的连接池,否则哨兵已经切换,业务仍连接旧主库。Cluster 报
CROSSSLOT不要简单关闭集群模式绕过。 典型现象是批量MGET、事务MULTI或 Lua 脚本在测试环境可用,上线后部分用户报错。根因是多个 key 被分配到不同哈希槽。修正方法是按业务聚合根设计 key,例如{user:1001}:profile、{user:1001}:cart;无法合并的批量操作应按槽分组后分别执行,而不是把所有 key 强行改成固定 hash tag,造成数据倾斜。副本只有数据,没有自动故障转移能力。 很多团队只部署主从,没有哨兵或 Cluster 管理,主库故障后手动执行
REPLICAOF NO ONE,恢复时间长且容易脑裂。修正方法是明确故障转移组件:中小规模使用 Sentinel,分片集群使用 Cluster,托管实例确认是否包含自动主备切换与切换告警。持久化策略不能只开 RDB 然后声称数据不丢。 RDB 是周期性快照,故障时可能丢失最近几分钟数据;AOF 重写期间磁盘 IO 升高,也可能影响延迟。修正方法是核心数据开启 AOF,评估
everysec的性能与丢失窗口,定期验证备份可恢复,并在云托管中确认备份保留天数、跨可用区备份与恢复 RTO。容量规划不要只看当前内存。 常见现象是 Redis 内存使用率到 70% 时业务仍正常,做一次 RDB、AOF 重写或流量突增后触发 OOM。修正方法是为复制全量同步、AOF 重写、写峰值和内存碎片预留 30% 到 50% 空间;Cluster 还要提前规划分片数,避免业务高峰期迁移槽导致延迟抖动。
最终建议很简单:单机能稳定承载且团队能接受少量运维,选哨兵;需要水平扩展且能改造多 key 使用方式,选 Cluster;希望把升级、备份、监控和切换交给平台,并愿意支付溢价,选云托管。先用决策矩阵排除错误方向,再用压测和故障演练验证,才是 Redis 高可用选型最稳妥的路径。
免责声明
本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。