前面介绍了 Redis 主从模型如何在不影响正常业务的情况下实现数据一致,若从库发生故障,客户端可以请求其他的从(或主)库读取数据,若主库发生故障,客户端就无法写入,而且还会影响从库的数据复制,这个时候就需要考虑主从切换,这篇文章就来学习下 Redis 哨兵机制和哨兵集群。
1.笔记图
2.Redis 从库切换为主库需要思考的问题
- 主库真的挂了吗?
- 该选择哪个从库作为主库?
- 怎么把新主库的相关信息通知给从库和客户端呢?
3.哨兵机制
- 说明:哨兵其实就是一个运行在特殊模式下的 Redis 进程,主从库实例运行的同时,它也在运行
- 职责:监控、选主、通知
3.1 监控
- 主库:如果主库也没有在规定时间内响应哨兵的 PING 命令,哨兵就会判定主库下线,然后开始自动切换主库的流程
- 主观下线:如果哨兵发现主库对 PING 命令的响应超时了,标记为主观下线
- 客观下线:只有大多数的哨兵实例,都判断主库已经主观下线了,主库才会被标记为客观下线,当有 N 个哨兵实例时,最好要有 N/2 + 1 个实例判断主库为 主观下线,才能最终判定主库为 客观下线
- 从库:如果从库没有在规定时间内响应哨兵的 PING 命令,哨兵就会把它标记为下线状态
3.2 选主
- 说明:主库挂了以后,哨兵就需要从很多个从库里,按照一定的规则选择一个从库实例,把它作为新的主库
- 选主规则:
- 检查从库当前在线状态,还需要判断之前网络连接状态,如配置 down-after-milliseconds * 10 表示如果发生断连超过 10 次,不适合选为新主库
- 第一轮:优先级最高的得分高,如配置 slave-priority 设置从库的优先级
- 第二轮:和原来的断开的主库同步数据最接近的得分高,判断 repl_backlog_buffer 中的master_repl_offset 和 slave_repl_offset 位置
- 第三轮:在优先级和复制进度都相同的情况下, ID 号最小的会被选为新主库
3.3 通知
- 哨兵会把新主库的连接信息发给其他从库,让它们执行 replicaof 命令,从新去新主库建立连接,同步数据
Tips:主从切换引发的思考:如果有哨兵实例在运行时发生了故障,主从库还能正常切换吗?
4.笔记图
5.Redis哨兵集群建立过程
5.1 功能说明
- 哨兵其实就是一个运行在特殊模式下的 Redis 实例,主从库实例运行的同时,它也在运行,多个实例可组成哨兵集群
- 即使有哨兵实例出现故障挂掉了,其他哨兵还能继续协作完成主从库切换的工作
- 它的职责是监控、选主、通知
5.2 Redis 如何配置哨兵
- 给Redis增加配置项,设置主库的 IP 和端口号
- sentinel monitor <master-name> <ip> <redis-port> <quorum>
6.Redis 哨兵集群组成原理
- 哨兵之间可以相互发现,基于 pub/sub 机制
- 哨兵基于 pub/sub 机制和主库建立连接,从主库上订阅消息和发布消息(如
IP
和端口) - 哨兵之间建立连接:
- 只有订阅了同一个频道的哨兵,才能发布/订阅信息交换,并且不影响客户端此功能
- __sentinel__:hello 频道用于哨兵互相通信频道(客户端发布/订阅使用另外频道)
- 哨兵和从库建立连接(连接后监控从库):
- 哨兵给主库发送 INFO,主库就会把从库列表返回给哨兵
- 哨兵可以根据从库列表信息和每个从库连接,并对从库进行监控
- 哨兵和客户端建立连接(连接后可通知):
- 每个哨兵实例也会提供 pub/sub 机制
- 客户端可以从哨兵订阅消息
- 哨兵提供的消息订阅频道,不同频道包含了主从库切换过程中的不同关键事件
- 举例
# 订阅“所有实例进入客观下线状态的事件” SUBSCRIBE +odown # 订阅所有的事件 PSUBSCRIBE *
- 若客户端看到 switch-master,表示这个事件主库已经切换了,新主库的
IP
地址和端口信息已经有了,客户端就可以用这里面的新主库地址和端口进行通信了
7.Redis哨兵选Leader
- 判断客观下线:
- 任何一个哨兵实例只要判断主库主观下线,就会给其他哨兵实例发送 is-master-down-by-addr 命令
- 收到 is-master-down-by-addr 命令的实例会根据自己和主库的连接情况,做出 Y 或 N 的响应(Y 赞成,N 反对)
- 哨兵获得了仲裁所需的赞成票数后,就可以标记主库为客观下线,这个所需赞成票通过 quorum 配置项决定,如 quorum 配置为 3,则该哨兵判断主库客观下线需要 3 票赞成(包括了自己的1票)
- Leader 选举
- 哨兵拿到赞成主库下线的票数大于等于 quorum,就确定了主库客观下线
- 哨兵就可以再给其他哨兵发送命令,表明希望由自己担任执行主从切换的 Leader
- 在投票过程中,任何一个想成为 Leader 的哨兵,要满足两个条件:拿到半数以上的赞成票和拿到的票数同时还需要大于等于哨兵配置文件中的 quorum值
- Leader选举举例:
- T1时刻:A 判断主库为客观下线,它想成为 Leader,就先给自己投 1 张赞成票,然后分别向 B 和 C 发送命令,表示要成为 Leader
- T2时刻:C 判断主库为客观下线,它也想成为 Leader,所以也先给自己投 1 张赞成票,再分别向 A 和 B 发送命令,表示要成为 Leader
- T3 时刻:A 收到了 C 的 Leader 投票请求。因为 A 已经给自己投了 1 票 Y,所以它不能再给其他哨兵投赞成票了,所以 A 回复 N 表示不同意。同时,B 收到了 T2 时 C 发送的 Leader 投票请求。因为 B 之前没有投过票,它会给第一个向它发送投票请求的哨兵回复 Y,给后续再发送投票请求的哨兵回复 N,所以,在 T3 时,B 回复 C,同意 C 成为 Leader
- T4 时刻:B 才收到 T1 时 A 发送的投票命令。因为 B 已经在 T3 时同意了 C 的投票请求,此时,B 给 A 回复 N,表示不同意 A 成为 Leader。发生这种情况,是因为 C 和 B 之间的网络传输正常,而 A 和 B 之间的网络传输可能正好拥塞了,导致投票请求传输慢了
- T5 时刻:A 得到的票数是来自它自己的 1 票 Y 和来自 B 的 1 票 N。而 C 除了自己的赞成票 Y 以外,还收到了来自 B 的一票 Y。此时,C 不仅获得了半数以上的 Leader 赞成票,也达到预设的 quorum 值(quorum 为 2),所以它最终成为了 Leader。接着,C 会开始执行选主操作,而且在选定新主库后,会给其他从库和客户端通知新主库的信息
Tips:注意坑:要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds,否则导致哨兵集群一直没有对有故障的主库形成共识,也就没有及时切换主库,最终的结果就是集群服务不稳定。