type
status
date
slug
summary
tags
category
icon
password
创建时间
Sep 19, 2024 04:03 PM
哨兵机制的基本流程
哨兵是就是 Redis 的一个进程,在主从实例运行时,它也在运行。哨兵负责三个任务:监控、选主(选择主库)、通知。
- 监控。
- 周期性地向所有主从库发送 PING 命令,检测它们是否仍然在线运行。主从库在规定时间中,没有响应 PING 命令,哨兵会把其标记为“下线状态”。
- 而当判定主库下线,会进入下一个流程──切换主库。
- 选主。从众多从库中,按照一定规则选择一个从库实例,当作新的主库。
- 通知。
- 哨兵将新主库的连接信息发送给其他从库,让它们执行
replicaof
命令,和新主库建立连接,并进行数据复制。 - 同时,哨兵将新主库的连接信息通知给客户端,让它们把请求发到新主库上。
哨兵需要做的两个决策:
- 在监控任务中,哨兵需要判断主库是否处于下线状态;
- 在选主任务中,哨兵也要决定选择哪个从库实例作为主库。
主观下线和客观下线
主观下线:单个哨兵通过主从库对
PING
命令的响应情况,判断主从库是否下线。客观下线:多数哨兵,都判断主库已经“主观下线”,主库会被标记为“客观下线”。少数服从多数。

如何选择新主库?
- 筛选:在多个从库中,先按照一定的筛选条件,把不符合条件的从库去掉。
- 筛选的条件
- 检查从库的当前在线状态
- 判断从库之前的网络连接状态
- 具体操作:使用配置项
down-after-milliseconds
* 10 down-after-milliseconds
是我们认定主从库断连的最大连接超时时间。如果在down-after-milliseconds
毫秒内,主从节点都没有通过网络联系上,我们就可以认为主从节点断连了。- 如果发生断连的次数超过了 10 次,就说明这个从库的网络状况不好,不适合作为新主 库。
- 打分:按照一定的规则,给剩下的从库逐个打分,将得分最高的从库选为新主库
- 打分规则:按照从库优先级、从库复制进度、从库 ID 号依次进行。只要在某一轮中,有从库得分最高,那么它就是主库了,选主过程到此结束。如果没有出现得分最高的从库,那么就继续进行下一轮。
- 第一轮:优先级最高的从库得分高。
- 第二轮:和旧主库同步程度最接近的从库得分高。
- 第三轮:ID 号小的从库得分高。
通过
slave-priority
配置项,给不同的从库设置不同优先级。在主从库同步时的命令传播过程,主库会用
master_repl_offset
记录当前的最新写操作在 repl_backlog_buffer
中的位置,而从库会用 slave_repl_offset
这个值记录当前的复制进度。从库的
slave_repl_offset
最接近 master_repl_offset
,那么它的得分就最高,可以作为新主库。主库都挂了,怎么获取主库的
master_repl_offset
值?对
master_repl_offset
本身的理解没错,master_repl_offset
是单调增加的,它的值可以大于repl_backlog_size
。Redis会用一个名为repl_backlog_idx
的值记录在环形缓冲区中的最新写入位置。举个例子,例如写入len的数据,那么master_repl_offset
+= len
repl_backlog_idx
+= len
但是,如果
repl_backlog_idx
等于repl_backlog_size
时,repl_backlog_idx
会被置为0,表示从环形缓冲区开始位置继续写入。而在实际的选主代码层面,sentinel 是直接比较从库的slave_repl_offset
,来选择和主库最接近的从库。我的理解是
master_repl_offset
是单调递增的,是可以大于 repl_backlog_size
,Redis 单独使用 repl_backing_idx
记录环形缓冲区中最新写入位置,而 repl_backing_idx
是循环递增的。当写入新数据时,两者的长度是都要变化的,不同的是,repl_backing_idx
等于 repl_backlog_size
时,会被置为 0。因此,在实际选主的时候,可以直接比较从库的 slave_repl_offset
即可。这个值谁最大,谁的得分高。
问题
问题 1:在主从切换过程中,客户端能否正常地进行请求操作呢?
对于读请求,有从库可以进行响应;写请求,需要等待确定完主库,才能正常响应。
问题 2:如果想要应用程序不感知服务的中断,还需要哨兵或客户端再做些什么吗?