⭐最核心的结论:所谓选举的过程不是直接选出新的主节点,而是先在哨兵节点中选出 leader ,再由 leader 负责后续主节点的指定。
假定当前环境:
三个哨兵(sentenal1, sentenal2, sentenal3)
一个主节点(redis-master)
两个从节点(redis-slave1, redis-slave2)
当主节点出现故障,就会触发以下一系列过程:
一、判定主观下线
哨兵节点通过心跳包判定 redis-master 服务器是否正常工作。如果心跳包没有如约而至,那么这个哨兵节点就会认为 redis-master 服务器挂了,这就是主观下线(SDown)。
注意,此时在在某一个哨兵节点的角度,还不能排除网络波动的对心跳包丢失的影响,所以只能是该哨兵节点单方面认为这个 redis-master 节点挂了,是“主观”的。
二、判定客观下线
此时,哨兵 sentenal1,sentenal2,sentenal3 均会对主节点故障这件事情进行投票。当故障得票数 >= 配置的法定票数之后,哨兵们就认为这个主节点确实挂了,即触发客观下线(ODown)。
法定票数可以在哨兵节点的配置文件中查看:
sentinel1.conf是哨兵节点sentinel1的配置文件
有些同学可能会有疑问,是否存在一种情况:出现非常严重的网络波动,导致所有的哨兵都联系不上 redis 主节点从而“误判”成主节点挂了呢?
当然是有的!然而,如果出现这个情况,怕是连用户的客户端也连不上 redis 主节点了,此时这个redis主节点基本也是无法正常工作的。
注意,“挂了”不一定指的就是进程崩了。只要无法正常访问主节点,都可以视为是主节点挂了。
三、选举出哨兵的 leader
接下来需要哨兵把剩余的 slave 中挑选出⼀个新的 master。
这个工作不需要所有的哨兵都参与,只需要选出个代表(称为 leader),由 leader 负责进行 slave 升级到 master 的提拔过程。这个选举的过程涉及到 Raft 算法。
假定⼀共三个哨兵节点 S1,S2,S3:
1、每个哨兵节点都给其他所有哨兵节点发起⼀个 “拉票请求”。
即 S1 -> S2,S1 -> S3;S2 -> S1,S2 -> S3;S3 -> S1,S3 -> S2。
2、收到拉票请求的节点会回复⼀个 “投票响应”,响应的结果有两种可能,即投 or 不投。
比如 S1 给 S2 发了投票请求,S2 就会给 S1 返回投票响应。S2 是否要投 S1 ,取决于 S2 是否给别人投过票了. (每个哨兵只有一票). 如果 S2 没有给别人投过票,也就是说 S1 是第一个向 S2 拉票的,那么 S2 就会投 S1,否则则不投。
3、一轮投票完成之后,得票超过半数的哨兵节点将动成为 leader。
如果出现平票的情况 (如 S1 投 S2,S2 投 S3,S3 投 S1,每人一票),就重新再投一次。
这也是一般建议哨兵节点设置成奇数个的原因:如果是偶数个,就增大了平票的概率,从而带来不必要的开销。
***选举leader的流程演示:
leader选举总结:Raft 算法的核心是 “先下手为强”,谁率先发出了拉票请求,谁就有更大的概率成为 leader。这里的决定因素是 “网络延时”,网络延时本身就带有一定的随机性。
4、leader 节点负责挑选一个 slave 成为新的 master。
当其他的 sentenal 发现新的 master 出现了, 就说明选举结束了。
四、由leader挑选一个从节点作为新的主节点
举个栗子:
假设一个情景:学校里有一位任课老师请假不能来给学生上课,需要由别的任课老师从众多助教老师中选择一位来代替他上课。
- 任课老师有很多,谁来当负责人来负责挑选合适的助教老师? ——即众多哨兵节点选举leader的过程。
- 如何怎样的助教老师是合适的? ——即由leader哨兵节点从所有redis-slave节点中选择一个作为新的redis-master的过程。(接下来介绍的)
挑选的规则
leader如何挑选新的主节点?按照优先级 > offset > run id的次序依次筛选:
- 优先级最高的从节点胜出。每个redis数据节点都会在配置文件中有一个优先级配置(slave-priority,默认情况下都相同)。【某个助教老师是校长钦定的,那就选他代替上课。】
- offset最大的从节点胜出。offset代表从节点从主节点这里同步数据的进度。数值越大,说明从节点的数据和主节点就越接近。【哪个助教老师的备课进度更多,哪个助教老师就来代替上课。】
- run id值更小的胜出。run id是每个redis节点启动的时候随机生成的一串数字(大小全凭缘分)。此时意味着优先级和offset都一样,那么选谁都可以,其实就是随便挑一个。【看哪个助教老师名字好听,就选谁来代替上课。】
把新的主节点指定好了之后:
- leader就会控制这个这个节点执行slave no one,成为 master;
- 再控制其他节点执行 slave of,让这些其他节点认新的 master 为主节点。
*哨兵节点的作用演示
我们知道,哨兵存在的意义是,在redis主从结构出现问题(比如主节点挂了)时,哨兵节点能够自动重选出一个新的主节点来代替之前挂了的主节点,从而保证整个 redis 仍然是可用状态。
以下是在centos7上,采用docker配置了3个redis数据节点(1个redis-master,2个redis-slave)和3个哨兵节点(redis-sentinel)后的演示过程:
1、首先查看正在运行的容器:docker ps -a
可见所有容器都已启动
2、手动停止主节点,模拟主节点掉线:docker stop redis-master
手动停止redis-master后,再次查看docker运行情况,可见redis-master已停止运行
3、 此时主节点已经是退出状态。事实上当主节点挂了后,哨兵节点就已经开始工作了。查看哨兵节点的日志:docker-compose logs
4、此时连接6379(即刚才手动下线了的主节点),发现连不上,证明原来的主节点确实已经下线:
5、改连redis节点6380,连接成功并查询信息发现,6380仍然是一个slave节点,且其主节点IP已经成为了172.18.0.3(而不再是原来的172.18.0.2):
6、6380无法设置值(只读),说明它确实仍然是一个从节点:
7、退出6380,再连接redis节点6381,查看info replication发现,本来是从节点的6381已经变成了主节点:
8、此时也就可以顺利地在6381上进行值的写入操作,进一步证明6381已经具备了主节点的功能:
9、此时如果再把原来挂了的主节点6379恢复正常,虽然6379恢复上线,但它的主节点身份在挂了的时候就失去了,已经变成了一个从节点,即使重新启动也不会变回主节点:
10、查看当前新主节点6381的信息,可见现在有两个从节点(6380和6379)连接在它身上: