自托管里,Redis 往往承担着一个尴尬又关键的角色:缓存、会话、队列、限流计数全压在这一台内存服务上。它快是快,但一旦这台 Redis 挂了,全部依赖它的服务会同时"塌":缓存击穿、会话失效、业务停顿。Redis 自带的高可用方案——主从复制 + 哨兵(Sentinel),以及集群(Cluster),回答的正是"让我 Redis 坏得起、主库切换对应用无感"。这篇讲清哨兵与集群解决什么、怎么搭、怎么让应用感知切换,以及常见坑与边界。
一、Redis 高可用解决什么:让"这台内存服务"坏得起、切换无感
Redis 是单线程、纯内存,快到极致,但也意味着"单点"一旦出问题影响是全员的。提高可用的核心思路是"多副本 + 自动切换":给主库配从库(复制数据),再用哨兵去监控主从——当主库故障时,哨兵自动把某个从库提升为主(failover),并告诉应用新的主是谁。这样 Redis 的主节点坏了,秒级完成切换,应用不用等修复、不用手工改配置,几乎无感。Redis 的可用因此从"单点靠运气"变成"多副本 + 自动故障转移"。
另一条路是 Redis Cluster:数据自动分片到多个主节点,每个分片配从节点,节点之间自动选举、容灾。Cluster 解决的不只是可用,还有"容量与吞吐的水平扩展"——单机内存装不下、单线程打不满时,把数据分片到多台。对自托管,多数场景"哨兵"就够:数据量不大、要的是稳定可用;只有当数据量/吞吐大到单机顶不住,才值得上 Cluster。
二、Redis 哨兵怎么搭:一主多从 + 一组哨兵 + 自动故障转移
哨兵架构由三部分组成:一主(写入)+ 一从或多从(复制备份)+ 至少三个哨兵(监控并决策)。哨兵通过主观下线(sdown)与客观下线(odown,多个哨兵一致认为主挂)来判断故障,再发起故障转移:从候选从库里挑一个提升为新主、改其他从库指向新主、并通知应用更新。关键点:哨兵要 ≥3 个并奇数个,才能在做"选主"这类多数派决策时不出现脑裂;而应用要连的是哨兵(Sentinel),由它返回当前主地址,而不是直接写死主库。
# sentinel.conf 关键点(每个哨兵节点都配)
sentinel monitor mymaster 127.0.0.1 6379 2
# 名字 主库地址端口 quorum(客观下线的哨兵数)
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 30000
# 应用连法:不要直连主库,而是问哨兵"现在主是谁"
redis-cli -h 哨兵IP -p 26379 -a 密码 SENTINEL get-master-addr-by-name mymaster
# 返回 主库IP 主库端口 —— failover 后会自动变成新主
这里最容易出错的是"应用仍直连主库":哨兵的价值不止"自动提升主",更在于"应用从哨兵动态获知当前主"。如果应用把主库地址写死,failover 时应用还连着旧主(已挂或已降为从),照样失控。所以用哨兵,一定要让客户端走 Sentinel 机制(很多客户端库原生支持传入哨兵列表 + master 名),或至少通过一层能感知切换的入口。
三、Redis Cluster 什么时候上:分片扩展,但复杂度更高
Cluster 把 16384 个哈希槽(slot)分配给多个主节点,key 按 CRC16 哈希落到某个槽,从而落在对应主节点;每个分片配从节点做容灾。它一次解决"容量不够(分片)"与"主挂可切换(从节点提升)"。代价是复杂度明显上升:要么用 Cluster-aware 客户端(RedisCluster 客户端),要么用 Redis 官方 Cluster proxy;且多键操作(MULTI/事务/批量)只在该组槽内有效,跨槽命令要分片考虑。所以判断"上不上 Cluster"不该跟风:数据量小、单机能放下的,哨兵即可;只有到单机内存/CPU 真成瓶颈,才值得为分片承担复杂度。
# 用 redis-trib / 官方工具建一个最小 3 主 3 从 集群示意
redis-cli --cluster create \
192.168.1.11:6379 192.168.1.12:6379 192.168.1.13:6379 \
192.168.1.14:6379 192.168.1.15:6379 192.168.1.16:6379 \
--cluster-replicas 1
# Cluster 客户端要点:直接连任意一个节点,由客户端做 slot→节点路由
# redis-cli -c -h 192.168.1.11 -p 6379 -a 密码 # -c 开启集群模式
Cluster 的坑集中在客户端与槽位:普通 redis-cli 直连在 key 落在别的节点时会返回 MOVED 重定向错误,必须用 Cluster-aware 客户端(`-c` 或专用库);批量/事务要小心跨槽限制;扩缩容用官方 `cluster reshard` 在线迁移槽,别手工乱动。对多数自托管,把 Cluster 当"数据大到单机真放不下时"的最后一张牌,平时哨兵一项往往已够。
四、常见坑:脑裂、直连主库、密码/ACL、监控与持久化
哨兵/集群跑起来,四个坑要防。一是"脑裂":哨兵不足 3 或 quorum 配错,可能多套主并存、两部分同时写入——quorum 与节点数要按多数派设计。二是"应用直连主库"已说过:failover 后应用不感知,等于高可用白搭,客户端必须走 Sentinel/Cluster-aware。三是"密码与 ACL":主从之间、哨兵与 Redis 之间的认证要配齐,ACL 权限按需最小化,别让复制链路或哨兵成为被利用的口。四是"监控与持久化":AOF/RDB 持久化仍要做(副本多了也要真正能恢复,别当冗余就以为安全),并把哨兵切换、主从状态、延迟纳入监控告警——高可用不是说"不用看了",而是"出了问题能自动救 + 能被看见"。
# Redis 集群开启节点自动主从切换(保护副本可提升)
# --cluster-require-full-coverage no # 允许部分分片挂掉也能对外(牺牲一致性)
# --appendonly yes # 持久化保底,别把它当"纯缓存"就不设
把这当排障 SOP:failover 后先看"新主是谁、从库是否重新指向、应用连的是不是新主",再看哨兵日志里的切换原因,最后确认脑裂没发生(没有两个主同时服务)。高可用的价值只在你"切换能无感 + 失败能被看见"时才成立,否则只是一个静态的多副本摆在那。
五、边界:哨兵/集群保"可用",不保"数据零丢失"也不解决写扩展
高可用的边界要认清:副本与 failover 提升的是"可用性"(主挂了能切),但不保证数据零丢失——Redis 复制的异步性决定故障瞬间可能有少量未同步写入丢在旧主;要严格更低的丢失要用 WAIT 等同步复制机制(代价是性能)。其次,哨兵解决不了写扩展,写仍集中在新主;真要写多点才上 Cluster 分片。再者,Redis 无论怎么高可用,都只是缓存/会话层,你的"权威数据"仍在数据库并靠数据库的备份兜底——别把 Redis 的高可用当成"数据安全"。
把 Redis 高可用放回自托管整体:它让"缓存/会话/队列"这层从"单点靠运气"变成"多副本 + 自动切换"。落地要点:数据量可控用哨兵,配一主多从 + ≥3个奇数哨兵 + quorum 正确,应用走 Sentinel 动态获知主;数据大到单机顶不住再上 Cluster,接受其客户端与槽位复杂度;防住脑裂、直连主库、认证/ACL、监控持久化四坑,并认清它保可用不保零丢失、也不解决写单点。当你把 Redis 从"脆弱的单点"养成了"坏了能自愈"的服务,自托管的一堆依赖 Redis 的业务才真正站得稳。
结语
Redis 哨兵与集群的价值,是把"缓存/会话/队列这层内存服务"从单点靠运气升级为"多副本 + 自动故障转移"。落地要点:多数场景用哨兵——一主多从 + ≥3 个奇数哨兵 + 正确 quorum,应用必须走 Sentinel 动态获知当前主,failover 秒级且无感;数据大到单机顶不住才上 Cluster,接受分片与槽位复杂度并配 Cluster-aware 客户端;防住脑裂、应用写死主库、认证/ACL 缺失、忽略监控持久化四坑,并认清它提升的是可用性而非数据零丢失、也不解决写扩展。当 Redis 从"挂了全员陪葬"变成"坏了能自愈、切换无感、失败可见",自托管里依赖它的一整层业务才算真正有底气。



