Redis 学习笔记 - 哨兵

Redis 主从复制模式下,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址,对于很多应用场景这种故障处理的方式是无法接受的。Redis 从 2.8 开始正式提供了 Redis Sentinel(哨兵)架构来解决这个问题,本文对于 Redis Sentinel 做出简单介绍。

基本概念

主从复制的问题

Redis 主从复制模式可以将主节点的数据改变同步给从节点,这样从节点就可以起到两个作用:第一,作为主节点的一个备份,一旦主节点出了故障不可达的情况,从节点可以作为后备提供服务,保证数据尽量不丢失(主从复制是最终一致性)。第二,从节点可以扩展主节点的读能力,一旦主节点不能支撑住大并发量的读操作,从节点可以在一定程度上帮助主节点分担读压力。

但是主从复制也带来了以下问题:

  • 一旦主节点出现故障,需要手动将一个从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令其他从节点去复制新的主节点,整个过程都需要人工干预。
  • 主节点的写能力受到单机的限制。
  • 主节点的存储能力受到单机的限制。

高可用

Redis 主从复制模式下,一旦主节点出现了故障不可达,需要人工干预,故障转移实时性和准确性上都无法得到保障。Redis主从复制模式下的主节点出现故障后,进行故障转移的过程如下所示:

  1. 主节点发生故障后,客户端 (client) 连接主节点失败,两个从节点与主节点连接失败造成复制中断;
  2. 如果主节点无法正常启动,需要选出一个从节点 (slave-1),对其执行 slaveof no one 命令使其成为新的主节点;
  3. 原来的从节点(slave-1)成为新的主节点后,更新应用方的主节点信息,重新启动应用方;
  4. 客户端命令另一个从节点(slave-2)去复制新的主节点(new-master);
  5. 待原来的主节点恢复后,让它去复制新的主节点。

Redis Sentinel 的高可用性

当主节点出现故障时,Redis Sentinel 能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用。

Redis Sentinel 是一个分布式架构,其中包含若干个 Sentinel 节点和 Redis 数据节点,每个 Sentinel 节点会对数据节点和其余 Sentinel 节点进行监控,当它发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,它还会和其他 Sentinel 节点进行“协商”,当大多数 Sentinel 节点都认为主节点不可达时,它们会选举出一个 Sentinel 节点来完成自动故障转移的工作,同时会将这个变化实时通知给 Redis 应用方。整个过程完全是自动的,不需要人工来介入,所以这套方案很有效地解决了 Redis 的高可用问题。

从逻辑架构上看,Sentinel 节点集合会定期对所有节点进行监控,特别是对主节点的故障实现自动转移。整个故障转移的处理逻辑有下面4个步骤:

  1. 主节点出现故障,此时两个从节点与主节点失去连接,主从复制失败;
  2. 每个 Sentinel 节点通过定期监控发现主节点出现了故障;
  3. 多个 Sentinel 节点对主节点的故障达成一致,选举出其中一个 Sentinel 节点作为领导者负责故障转移;
  4. Sentinel 领导者节点执行了故障转移,整个过程和主从复制的场景下是完全一致的,只不过是自动化完成的。

Redis Sentinel 具有以下几个功能:

  • 监控:Sentinel 节点会定期检测 Redis 数据节点、其余 Sentinel 节点是否可达;
  • 通知:Sentinel 节点会将故障转移的结果通知给应用方;
  • 主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系;
  • 配置提供者:在 Redis Sentinel 结构中,客户端在初始化的时候连接的是 Sentinel 节点集合,从中获取主节点信息。

实现原理

节点发现

Redis Sentinel 通过三个定时监控任务完成对各个节点发现和监控:

  1. 每隔 10 秒,每个 Sentinel 节点会向主节点和从节点发送 info 命令获取最新的拓扑结构;
  2. 每隔 2 秒,每个 Sentinel 节点会向 Redis 数据节点的 __sentinel__:hello 频道上发送该 Sentinel 节点对于主节点的判断以及当前 Sentinel 节点的信息,同时每个 Sentinel 节点也会订阅该频道,来了解其他 Sentinel 节点以及它们对主节点的判断;
  3. 每隔 1 秒,每个 Sentinel 节点会向主节点、从节点、其余 Sentinel 节点发送一条 ping 命令做一次心跳检测,来确认这些节点当前是否可达。

节点选举

Redis Sentinel 使用了 Raft 算法实现领导者选举,大致思路如下:

  1. 每个在线的 Sentinel 节点都有资格成为领导者,当它确认主节点主观下线时候,会向其他 Sentinel 节点发送 sentinel is-master-down-by-addr 命令,要求将自己设置为领导者。
  2. 收到命令的 Sentinel 节点,如果没有同意过其他 Sentinel 节点的 sentinel is-master-down-by-addr 命令,将同意该请求,否则拒绝;
  3. 如果该 Sentinel 节点发现自己的票数已经 >= max(quorum, num(sentinels) / 2 + 1),那么它将成为领导者;
  4. 如果此过程没有选举出领导者,将进入下一次选举。

故障转移

领导者选举出的 Sentinel 节点负责故障转移,具体步骤如下:

  1. 在从节点列表中选出一个节点作为新的主节点,选择方法如下:
    • 过滤:“不健康”(主观下线、断线)、5 秒内没有回复过 Sentinel 节点 ping 响应、与主节点失联超过 down-after-milliseconds*10 秒;
    • 选择 slave-priority (从节点优先级) 最高的从节点列表,如果存在则返回,不存在则继续;
    • 选择复制偏移量最大的从节点(复制的最完整),如果存在则返回,不存在则继续;
    • 选择 runid 最小的从节点;
  2. Sentinel 领导者节点会对第一步选出来的从节点执行 slaveof no one 命令让其成为主节点;
  3. Sentinel 领导者节点会向剩余的从节点发送命令,让它们成为新主节点的从节点,复制规则和 parallel-syncs 参数有关;
  4. Sentinel 节点集合会将原来的主节点更新为从节点,并保持着对其关注,当其恢复后命令它去复制新的主节点。

参考资料

sentinel