Redis 哨兵机制

Redis 哨兵机制#

原理#

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

Redis 哨兵机制

基本的故障转移流程:

  1. 主节点出现故障,此时从节点失去连接,主从复制失败。
  2. 每个 Sentinel 节点通过定期监控发现主节点出现了故障

Redis 哨兵机制

  1. 多个 sentinel 节点对主节点的故障达成一致选举出其中一个节点作为领导者负责故障转移

Redis 哨兵机制

  1. Sentinel 领导者节点执行了故障转移,整个过程基本是跟我们手动调整一致的,只不过是自动化完成的

Redis 哨兵机制

  1. 故障转移后整个 Redis Sentinel 的结构,重新选举了新的主节点。
    Redis 哨兵机制

Redis Sentinel 具有以下几个功能:

  • 监控:Sentinel 节点会定期检查 Redis 数据节点、其余 Sentinel 节点是否可达

  • 通知:Sentinel 节点会将故障转移的结果通知给应用方

  • 主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系

  • 配置提供者: 在 Redis Sential 结构中,客户端在初始化的时候连接的是 Sentinel 节点集合,从中获取主节点的信息
    同时 Redis Sentinel 包含了若个 Sentinel 节点,这样做也带来了两个好处:

    • 对于节点的故障判断是由多个 Sentinel 节点共同完成,这样可以有效地防止误判
    • Sentinel 节点集合是由若干个 Sentinel 节点组成的,这样即使个别 Sentinel 节点不可用,整个 Sentinel 节点集合依然是健壮的,但是 Sentinel 节点本身就是独立的 Redis 节点,只不过它们有一些特殊,它们不存储数据,只支持部分命令

    Sentinel 的核心配置#

Redis 哨兵机制

docker run -itd  --name  redis-slave2  --net mynetwork  -p 6381:6379  --ip 172.10.0.3  redis2 

 docker run -itd  --name  redis-slave3  --net mynetwork  -p 6382:6379  --ip 172.10.0.4  redis2 


 docker run -itd  --name  redis-sentinel1  --net mynetwork  -p 22530:26379  --ip 172.10.0.9  redis2 

 docker run -itd  --name  redis-sentinel2  --net mynetwork  -p 22531:26379  --ip 172.10.0.10   redis2 

 docker run -itd  --name  redis-sentinel3  --net mynetwork  -p 22532:26379  --ip 172.10.0.11   redis2

sentinel monitor mymaster 127.0.0.1 7000 2

监控的主节点的名字、IP 和端口,最后一个 2 的意思是有几台 Sentinel 发现有问题,就会发生故障转移,例如 配置为 2,代表至少有 2 个 Sentinel 节点认为主节点不可达,那么这个不可达的判定才是客观的。对于设置的越小,那么达到下线的条件越宽松,反之越严格。一般建议将其设置为 Sentinel 节点的一半加 1

sentinel down-after-millseconds mymaster 30000

这个是超时的时间(单位为毫秒)。打个比方,当你去 ping 一个机器的时候,多长时间后仍 ping 不通,那么就认为它是有问题

sentinel parallel-syncs mymaster 1

当 Sentinel 节点集合对主节点故障判定达成一致时,Sentinel 领导者节点会做故障转移操作,选出新的主节点,原来的从节点会向新的主节点发起复制操作,parallel-syncs 就是用来限制在一次故障转移之后,每次向新的主节点发起复制操作的从节点个数,指出 Sentinel 属于并发还是串行。1 代表每次只能复制一个,可以减轻 Master 的压力;

Redis 哨兵机制

sentinel auth-pass master-name password

如果 Sentinel 监控的主节点配置了密码,sentinel auth-pass 配置通过添加主节点的密码,防止 Sentinel 节点对主节点无法监控。

sentinel failover-timeout mymaster 180000
表示故障转移的时间

sentinel 支持的合法命令如下:
SENTINEL masters 显示被监控的所有 master 以及它们的状态.

SENTINEL master <master name> 显示指定 master 的信息和状态;

SENTINEL slaves <master name> 显示指定 master 的所有 slave 以及它们的状态;

SENTINEL get-master-addr-by-name <master name> 返回指定 master 的 ip 和端口,如果正在进行 failover 或者 failover 已经完成,将会显示被提升为 master 的 slave 的 ip 和端口。

SENTINEL failover <master name> 强制 sentinel 执行 failover,并且不需要得到其他 sentinel 的同意。但是 failover 后会将最新的配置发送给其他 sentinel。

实现#

Sentinel 的实现原理,主要分为以下几个步骤:

  1. 检测问题,主要讲的是三个定时任务,这三个内部的执行任务可以保证出现问题马上让 Sentinel 知道。

  2. 发现问题,主要讲的是主观下线和客观下线。当有一台 Sentinel 机器发现问题时,它就会主观对它主观下线,但是当多个 Sentinel 都发现有问题的时候,才会出现客观下线。

  3. 找到解决问题的人,主要讲的是领导者选举,如何在 Sentinel 内部多台节点做领导者选举,选出一个领导者。

  4. 解决问题,主要讲的是故障转移,即如何进行故障转移

问题检测
Sentinel 会执行以下三个定时任务
每 10 秒每个 Sentinel 对 Master 和 Slave 执行一次 Info Replication。

每 2 秒每个 Sentinel 通过 Master 节点的 channel 交换信息(pub/sub)。

每 1 秒每个 Sentinel 对其他 Sentinel 和 Redis 执行 ping

第一个定时任务,指的是 Redis Sentinel 可以对 Redis 节点做失败判断和故障转移,在 Redis 内部有三个定时任务作为基础,来 Info Replication 发现 Slave 节点,这个命令可以确定主从关系。
第两个定时任务,类似于发布订阅,Sentinel 会对主从关系进行判定,通过 sentinel:hello 频道交互。了解主从关系可以帮助更好的自动化操作 Redis。然后 Sentinel 会告知系统消息给其它 Sentinel 节点,最终达到共识,同时 Sentinel 节点能够互相感知到对方。

第三个定时任务,指的是对每个节点和其它 Sentinel 进行心跳检测,它是失败判定的依据。

主观下线和客观下线
Sentinel 会 ping 每个节点,如果超过 30 秒,依然没有回复的话,做下线的判断。
每个 Sentinel 节点对 Redis 节点失败的 “偏见”。之所以是偏见,只是因为某一台机器 30 秒内没有得到回复;
这个时候需要所有 Sentinel 节点都发现它 30 秒内无回复,才会达到共识。
领导者选举方式
1. 每个做主观下线的 sentinel 节点,会向其他的 sentinel 节点发送命令,要求将它设置成为领导者

2. 收到命令 sentinel 节点,如果没有同意通过其它节点发送的命令,那么就会同意请求,否则就会拒绝

3. 如果 sentinel 节点发现自己票数超过半数,同时也超过了 sentinel monitor mymaster 127.0.0.1 6379 2 超过 2 个的时候,就会成为领导者

4. 进行故障转移操作
如何选择 “合适的” Slave 节点
Redis 内部其实是有一个优先级配置的,在配置文件中 slave-priority,这个参数是 Salve 节点的优先级配置,如果存在则返回,如果不存在则继续。
当上面这个优先级不满足的时候,Redis 还会选择复制偏移量最大的 Slave 节点,如果存在则返回,如果不存在则继续。之所以选择偏移量最大,这是因为偏移量越小,和 Master 的数据越不接近,现在 Master 挂掉了,说明这个偏移量小的机器数据也可能存在问题,这就是为什么要选偏移量最大的 Slave 的原因。
如果发现偏移量都一样,这个时候 Redis 会默认选择 runid 最小的节点

生产环境中部署技巧#

  1. Sentinel 节点不应该部署在一台物理 “机器” 上。
  2. 部署至少三个且奇数个的 Sentinel 节点
    3 个以上是通过增加 Sentinel 节点的个数提高对于故障判定的准确性,因为领导者选举需要至少一半加 1 个节点,奇数个节点可以在满足该条件的基础上节省一个节点

常见问题#

  1. 异步复制导致数据丢失
    因为 master->slave 的复制是异步,所以可能有部分还没来得及复制到 slave 就宕机了,此时这些部分数据就丢失了。
  2. 集群脑裂导致数据丢失
    脑裂,也就是说,某个 master 所在机器突然脱离了正常的网络,跟其它 slave 机器不能连接,但是实际上 master 还运行着。
    造成的问题:
    此时哨兵可能就会认为 master 宕机了,然后开始选举,讲其它 slave 切换成 master。这时候集群里就会有 2 个 master,也就是所谓的脑裂。
    此时虽然某个 slave 被切换成了 master,但是可能 client 还没来得及切换成新的 master,还继续写向旧的 master 的数据可能就丢失了。
    因此旧 master 再次恢复的时候,会被作为一个 slave 挂到新的 master 上去,自己的数据会被清空,重新从新的 master 复制数据

解决

min-slaves-to-write 1
min-slaves-max-lag  10

要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒
如果说一旦所有的 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候,master 就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失

参考文献 redis.cn/topics/sentinel.html

本作品采用《CC 协议》,转载必须注明作者和本文链接
Luson
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。