3. Redis Sentinel 高可用:架构、选举、故障转移与客户端感知

在读写分离架构中,Redis Sentinel 是保障主节点故障时自动切换、维持写入入口高可用的核心组件。本章深入 Sentinel 的分布式哨兵架构、Leader 选举算法、故障转移流程以及客户端如何感知拓扑变化。

3.1 Sentinel 架构与核心职责

Sentinel 本身是一个独立运行的 Redis 特殊进程,通常部署 3 或 5 个实例组成哨兵集群。它不存储业务数据,只监控 Redis 数据节点的状态并执行管理动作。

职责 说明
监控 定期向所有主、从节点发送 PING,检测可达性与响应时间
通知 当被监控节点状态变化时,通过 Pub/Sub 或 API 通知管理员或客户端
自动故障转移 主节点不可达时,从剩余从节点中选举一个提升为新主,并修改其他从节点的复制目标
配置提供 客户端通过 Sentinel 获取当前主节点地址,实现动态发现
部署建议:Sentinel 至少部署 3 个实例(奇数),且分布在不同的物理机或可用区,避免脑裂时无法形成法定人数。

3.2 哨兵选举:Raft 风格的 Leader 选举

当 Sentinel 集群需要执行故障转移时,必须先选出一个 Leader 哨兵 来协调整个流程。选举基于 Raft 算法 的简化实现,核心步骤:

  1. 主观下线(SDOWN):单个 Sentinel 发现主节点 PING 无响应(down-after-milliseconds 超时)。
  2. 客观下线(ODOWN):该 Sentinel 向其他哨兵发送 SENTINEL is-master-down-by-addr 命令,当收到 法定人数(quorum) 的确认后,标记主节点为 ODOWN。
  3. 发起选举:检测到 ODOWN 的 Sentinel 自增本地 epoch(选举轮次),并向所有哨兵广播投票请求。
  4. 投票规则:每个 Sentinel 在每个 epoch 内只能投一票,先到先得;投票给请求中 runid 最大的哨兵(或最先收到的请求)。
  5. 成为 Leader:获得超过半数(N/2 + 1)投票的 Sentinel 成为 Leader,开始执行故障转移。
关键参数:quorum 通常设为 N/2 + 1(例如 3 个哨兵设 2,5 个哨兵设 3)。down-after-milliseconds 建议 5000~10000ms,避免网络抖动导致频繁切换。
Sentinel Leader 选举流程(Raft 简化) ① 主观下线 (SDOWN) ② 询问其他哨兵 ③ 客观下线 (ODOWN) ④ 发起选举 (epoch++) ⑤ 广播投票请求 ⑥ 投票(先到先得) ⑦ 成为 Leader(N/2+1) 说明:每个 epoch 内每个哨兵只能投一票,获得超过半数投票的哨兵成为 Leader 若平票则进入下一 epoch 重新选举,直到选出 Leader

3.3 故障转移机制:Leader 执行四步切换

Leader 哨兵被选出后,立即执行故障转移。整个过程分为四个严格顺序的阶段:

步骤 操作 详细说明
1 筛选从节点 排除已下线、断线时间超过 down-after-milliseconds * 10、与主节点复制延迟过大的从节点
2 选举新主节点 在剩余从节点中,按优先级(slave-priority)从低到高选择;优先级相同则选复制偏移量最大的(数据最新)
3 提升新主节点 向选中的从节点发送 SLAVEOF NO ONE,使其成为新主节点;等待其状态变为 master
4 重新配置从节点 向其他从节点发送 SLAVEOF new_master_ip new_master_port,使其复制新主节点;若原主节点恢复,也将其降级为从节点
注意:故障转移期间,原主节点写入的数据会丢失(异步复制)。读写分离架构中,从节点可能读到旧数据,需业务层容忍或使用 WAIT 命令同步复制。
Sentinel 故障转移四步流程 ① 筛选从节点 排除下线/延迟过高 ② 选举新主节点 优先级→复制偏移量 ③ 提升新主节点 SLAVEOF NO ONE ④ 重新配置 SLAVEOF 新主 原主节点恢复后,Sentinel 自动向其发送 SLAVEOF 新主节点,将其降级为从节点 整个切换过程对客户端透明,但写入新主前需重新发现 T0 T1 T2 T3

3.4 客户端感知:动态发现与连接管理

故障转移后,主节点 IP 发生变化。客户端不能硬编码主节点地址,必须通过 Sentinel 动态获取当前主节点信息。

3.4.1 客户端连接模式

  • 直接连接 Sentinel:客户端先连接 Sentinel 集群,通过 SENTINEL get-master-addr-by-name master_name 获取当前主节点地址。
  • 订阅变更通知:客户端订阅 Sentinel 的 +switch-master 频道,当主节点切换时收到推送,主动更新连接。
  • 连接池刷新:客户端维护一个主节点连接池,定期或通过回调刷新地址,避免使用失效连接。

3.4.2 常见客户端实现

客户端 Sentinel 支持方式 自动故障转移感知
Jedis (Java) JedisSentinelPool 内置 MasterListener 订阅 +switch-master,自动重建连接池
Lettuce (Java) RedisSentinelClient 基于响应式,支持拓扑刷新和重连
redis-py (Python) RedisSentinel 类 每次操作前检查主节点地址,或订阅变更
go-redis (Go) FailoverOptions 内置 Sentinel 监控,自动切换连接
最佳实践:客户端应设置连接超时(connectTimeout)和重试策略,避免在故障转移期间长时间阻塞。建议重试次数 3~5 次,间隔 100~500ms。

3.5 读写分离架构中的 Sentinel 配置示例

以下是一个典型的 Sentinel 配置文件(sentinel.conf)关键项:

# 监控的主节点名称、IP、端口、法定人数
sentinel monitor mymaster 192.168.1.10 6379 2

# 主观下线判定时间(毫秒)
sentinel down-after-milliseconds mymaster 5000

# 故障转移超时(毫秒)
sentinel failover-timeout mymaster 30000

# 并行同步的从节点数量(故障转移时)
sentinel parallel-syncs mymaster 1

# 保护模式(生产环境建议关闭或配置密码)
protected-mode no

# 哨兵之间通信的密码(可选)
sentinel auth-pass mymaster your_password
参数调优:parallel-syncs 设为 1 可减少故障转移期间从节点的同步压力;failover-timeout 应大于 down-after-milliseconds * 2 + 选举时间。

3.6 脑裂与数据丢失场景

Sentinel 无法完全避免脑裂(网络分区导致主节点和哨兵集群失联)。典型场景:

  • 主节点与哨兵集群网络中断:哨兵判定主节点下线,执行故障转移,提升新主节点。
  • 原主节点恢复网络:原主节点仍以 master 角色运行,但哨兵已将其降级为从节点。
  • 数据丢失:原主节点在分区期间写入的数据未同步到新主节点,恢复后这些数据被覆盖或丢失。
缓解措施:使用 min-slaves-to-write 和 min-slaves-max-lag 参数,限制主节点在从节点数量不足或延迟过大时拒绝写入,减少脑裂期间的数据丢失。

通过本章的学习,你应该能够独立部署 Sentinel 集群、理解选举与故障转移的底层机制,并指导客户端正确感知拓扑变化,为读写分离架构提供高可用保障。