Redis 哨兵机制与高可用实现
Redis哨兵是官方高可用方案。它监控主从集群,当主节点故障时,能自动选举新主并完成故障转移,保障服务不中断。
我们来详细、系统地讲解一下 Redis 的哨兵(Sentinel)机制。
什么是 Redis Sentinel (哨兵)?
Redis Sentinel 是 Redis 官方推荐的高可用性(High Availability, HA)解决方案。它是一个独立的进程,作用是监控一个或多个 Redis 主从(Master-Slave)集群,并在主服务器(Master)下线时,能够自动进行故障转移(Failover),将一个从服务器(Slave)提升为新的主服务器,并通知其他从服务器和客户端。
简单来说,哨兵就像一个“哨兵”或“守护者”,时刻监视着 Redis 主从集群的健康状况,并在“将军”(Master)阵亡时,从“副将”(Slaves)中推举一位新的“将军”,确保整个系统继续提供服务。
哨兵机制解决了什么问题?
在标准的 Redis 主从复制模式下,如果 Master 节点宕机,整个系统就无法处理写请求了。需要人工介入,手动将一个 Slave 提升为 Master,并修改其他 Slave 的配置以及客户端的连接配置。这个过程既耗时又容易出错。
哨兵机制就是为了解决这个问题,它实现了:
- 自动化:自动监控和故障转移,无需人工干预。
- 高可用:当主节点故障时,系统能在短时间内恢复写服务,最大程度地减少服务中断时间。
哨兵的核心功能
哨兵系统主要有以下四大核心功能:
- 监控 (Monitoring):哨兵会持续地向 Master、Slave 以及其他哨兵节点发送心跳检测(PING 命令),检查它们是否正常工作。
- 通知 (Notification):当被监控的某个 Redis 实例出现问题时,哨兵可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障转移 (Automatic Failover):当 Master 节点无法正常工作时,哨兵会启动一个故障转移过程。它会在所有的 Slave 节点中选举出一个作为新的 Master,并让其他的 Slave 节点去复制(Replicate)这个新的 Master。
- 配置提供者 (Configuration Provider):客户端在初始化时,不是直接连接 Redis Master 的 IP 地址,而是连接哨兵集群。哨兵会告诉客户端当前哪个节点是 Master。如果发生了故障转移,哨兵会通知客户端新的 Master 地址,从而实现客户端的无感知切换。
哨兵的工作原理
哨兵的工作原理可以分为以下几个关键阶段:
1. 监控与信息同步
哨兵集群(通常建议部署奇数个,如 3 个或 5 个)通过三个核心的定时任务来协同工作:
- 每 10 秒:每个哨兵向 Master 和 Slaves 发送
INFO命令。这可以帮助哨兵发现新的 Slave 节点,并获取所有节点的当前状态信息(如主从关系、复制偏移量等)。 - 每 2 秒:每个哨兵通过 Master 节点的
__sentinel__:hello发布/订阅频道,与其他哨兵交换信息。这使得哨兵们能够相互发现,并了解彼此对 Master 状态的判断。 - 每 1 秒:每个哨兵向所有 Redis 节点(包括 Master、Slaves 和其他哨兵)发送
PING命令,进行心跳检测。这是判断节点是否在线的主要依据。
2. 主观下线 (Subjective Down, SDown)
如果一个哨兵在配置的 down-after-milliseconds 时间内(例如 30000 毫秒)没有收到某个节点的有效 PING 回复,它就会单方面地认为这个节点已经主观下线(SDown)。
这个判断是主观的,因为可能仅仅是该哨兵与目标节点之间的网络出现了问题。
3. 客观下线 (Objective Down, ODown)
当一个哨兵将 Master 标记为 SDown 后,它会向其他哨兵发起询问,确认它们是否也认为 Master 已经下线。
当认为 Master 下线的哨兵数量达到配置的 quorum (法定数量) 时,该 Master 节点就会被标记为客观下线(ODown)。这个 quorum 值在哨兵配置文件中设置,例如 sentinel monitor mymaster 127.0.0.1 6379 2,这里的 2 就是 quorum。
这个机制是为了防止误判,只有大多数哨兵都认为 Master 出了问题,才会触发下一步的故障转移。
4. 选举领导者哨兵 (Leader Sentinel Election)
一旦 Master 被确认 ODown,哨兵们就需要选举出一个“领导者”(Leader)来负责执行故障转移。
选举过程基于 Raft 算法的变种:
- 第一个将 Master 标记为 ODown 的哨兵会向其他哨兵发送请求,希望自己成为 Leader。
- 其他哨兵如果还没有投票给别人,就会同意这个请求(一兵一票)。
- 如果某个哨兵获得了超过半数((N/2)+1,N为哨兵总数)的选票,它就成功当选为 Leader。
- 如果一轮选举没有成功,会稍等片刻,进入下一轮选举,直到选出 Leader。
5. 故障转移 (Failover)
领导者哨兵一旦选出,就开始执行故障转移,步骤如下:
挑选新的 Master:领导者哨兵会从所有的 Slave 节点中,按照一套规则挑选出最合适的节点作为新的 Master。挑选规则依次是:
- 优先级:
slave-priority配置值越小,优先级越高。 - 复制偏移量:优先级相同的情况下,选择复制偏移量(replication offset)最大的,代表它与旧 Master 的数据同步最完整。
- 运行 ID:如果以上两个条件都相同,则选择运行 ID(Run ID)最小的。
- 优先级:
提升为 Master:领导者哨兵对选出的 Slave 节点发送
SLAVEOF NO ONE命令,使其从 Slave 角色提升为 Master 角色。重新配置 Slaves:领导者哨兵向其余的 Slave 节点发送
SLAVEOF <new_master_ip> <new_master_port>命令,让它们去复制新的 Master。更新旧 Master:哨兵会继续监控旧的 Master。如果它重新上线,哨兵会向它发送
SLAVEOF命令,使其成为新 Master 的一个 Slave,防止出现“脑裂”(Split-brain)问题。
哨兵配置示例
一个简单的 sentinel.conf 配置文件如下:
# 哨兵进程的端口
port 26379
# 监控名为 mymaster 的主节点,其地址为 127.0.0.1:6379
# quorum (法定数量) 设置为 2,表示至少需要 2 个哨兵同意才能判断 Master 为 ODown
sentinel monitor mymaster 127.0.0.1 6379 2
# Master 被哨兵认定为 SDown 的超时时间(毫秒)
# 如果 5 秒内 Master 没有响应,则被认为是主观下线
sentinel down-after-milliseconds mymaster 5000
# 在故障转移期间,最多允许多少个 Slave 同时与新 Master 进行同步
# 这个数字越小,对新 Master 的负载压力越小
sentinel parallel-syncs mymaster 1
# 故障转移的超时时间(毫秒)
# 如果在这个时间内没有完成 failover,则认为本次 failover 失败
sentinel failover-timeout mymaster 60000
# 如果 Master 设置了密码,哨兵连接 Master 和 Slaves 时需要使用此密码
# sentinel auth-pass <master-name> <password>
# sentinel auth-pass mymaster YourPassword
客户端如何连接哨兵模式下的 Redis?
在哨兵模式下,客户端不应该硬编码 Master 的 IP 和端口。正确的做法是:
- 客户端连接到哨兵集群(可以提供一个或多个哨兵的地址)。
- 客户端向哨兵询问当前名为
mymaster的主节点地址。 - 哨兵返回当前 Master 的 IP 和端口。
- 客户端使用这个地址去连接 Master 进行数据操作。
- 大多数现代 Redis 客户端库(如 Jedis, Lettuce, redis-py 等)都内置了对哨兵模式的支持,能够自动完成上述过程,并在发生故障转移时自动获取新的 Master 地址。
优缺点
优点
- 高可用性:提供了自动化的故障发现和转移能力,是 Redis 主从模式高可用的基石。
- 部署简单:相对于 Redis Cluster,哨兵模式的部署和配置更简单。
- 监控和通知:不仅仅是故障转移,还提供了丰富的监控信息和通知机制。
缺点
- 资源浪费:在任何时候,只有一个 Master 节点在处理写请求,其他 Slave 节点主要用于备份和读扩展,写能力存在单点瓶颈。
- 故障转移有延迟:从 Master 宕机到故障转移完成,中间存在一个时间窗口(通常是秒级),在这个窗口内写服务是不可用的。
- 配置复杂性增加:相比单机模式,需要额外维护一个哨兵集群。
- 可能的数据丢失:由于主从复制是异步的,故障转移时,如果新 Master 的数据落后于旧 Master,可能会丢失一小部分已提交的写操作。
总结
Redis Sentinel 是一个强大而成熟的 Redis 高可用解决方案。它通过一个独立的哨兵集群来监控、通知和自动管理 Redis 主从集群,确保在主节点出现故障时能够快速、自动地进行故障转移,从而保障服务的连续性。对于需要高可用但又不想引入 Redis Cluster 复杂性的场景,哨兵模式是一个非常优秀的选择。