一、Redis主从复制中的问题
Redis主从复制集群可以将主节点的数据改变同步给从节点,这样从节点就可以起到两个作用:第一:作为主节点的一个备份,一旦主节点出了故障不能继续对外提供服务时,从节点可以作为后备"顶"上来,并且保证数据尽量不丢失。第二,从节点可以扩展主节点的读能力,通过实现读写分离结构,可以大大减轻主节点在进行高并发读写操作时的访问压力。
但是主从同步也带了一些问题:
-
一旦主节点故障,需要手动将一个从节点晋升为主节点,slaveof no one。
-
需要修改客户端或者应用程序的主节点地址。
-
如果是一主多从结构,还需将其他从节点调整,让其从新的主节点进行复制而以上整个过程都需要人工干预。
二、Redis高可用方案
Redis Sentinel是Redis的高可用实现方案,在实际的生产环境中,对提高整个系统的高可用性是非常有帮助的。哨兵是一个分布式架构,其中包含若干个Sentinel节点和Redis数据节点,每个Sentinel节点都会对数据节点和其他Sentinel节点进行监控,当他发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,他还会和其他Sentinel节点进行"协商",当半数以上Sentinel节点都认为主节点不可达时,它们会选举出一个Sentinel节点来完成自动故障转移的工作,同时会将这个变化实时通知给Redis的应用方。整个过程是完全自动的,不需要人工来介入,所以这套方案很有效的解决了Redis的高可用问题。

整个故障转移的处理逻辑基本上可分为4步:
-
主节点出现故障,此时两个从节点与主节点失去连接,主从复制失败
-
每个Sentinel节点通过定期监控发现主节点出现了故障
多个Sentinel节点对主节点的故障达成一致,选举出其中一个Sentinel节点作为领导者(leader)负责本次故障转移工作。
-
Sentinel领导者节点执行了故障转移,如下图所示

三、Sentinel实现原理
3.1、三个定时监控任务
Redis Sentinel通过三个定时监控任务完成对各个节点发现和监控:
- 每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新的拓扑结构,这个定时任务的作用具体可以表现在三个方面:
-
通过向主节点执行info命令,获取从节点的信息,这也是为什么Sentinel节点不需要显示配置监控从节点
-
当有新的从节点加入时都可以立刻感知出来
-
节点不可达或者故障转移后,可以通过info命令实时更新节点拓扑信息
- 每隔2秒,每个Sentinel节点会向Redis数据节点的sentinel:hello频道上发送该Sentinel节点对于主节点的判断以及当前Sentinel节点的信息,同时每个Sentinel节点也会订阅该频道,来了解其他Sentinel节点以及它们对主节点的判断,所以这个定时任务可以完成以下两个工作:
-
发现新的Sentinel节点:通过订阅主节点的sentinel:hello了解其他的Sentinel节点信息,如果是新加入的Sentinel节点,将该Sentinel节点信息保存起来,并与该Sentinel节点创建连接。
-
Sentinel节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据。
- 每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确认这些节点当前是否可达。
3.2、主观下线
每个Sentinel节点会每隔1秒对主节点、从节点、其他Sentinel节点发送ping命令做心跳检测,当这个节点超过down-after-milliseconds时间没有进行有效回复,Sentinel节点就会对该节点做失败判定,这个判定行为叫做主观下线。从字面意思也可以很容易看出主观下线是当前Sentinel节点的一家之言,存在误判断的可能。
3.3、客观下线
当Sentinel主观下线的节点是主节点时,该Sentinel节点会通过Sentinel is-master-down-by-addr命令向其他Sentinel节点询问对主节点的判断,当超过半数的Sentinel节点都认为主节点确实有问题,这时该Sentinel节点会做出客观下线的决定,这样客观下线的含义是比较明显了,也就是大部分Sentinel节点都对主节点的下线做了同意的判定,那么这个判定就是客观的。
3.4、领导者选举
故障转移的工作只需要一个Sentinel节点来完成即可,所以Sentinel节点之间会做一个领导者选举的工作,选出一个Sentinel节点作为领导者进行故障转移的工作。Redis使用了Raft算法实现领导者选举,大致思路如下:
-
每个在线的Sentinel节点都有资格成为领导者,当他确认主节点主观下线时,会向其他Sentinel节点发送sentinel is-master-down-by-addr命令,要求将自己设置为领导者。
-
收到命令的节点,如果没有同意过其他节点的请求,则会同意该请求,否则拒绝。
-
如果某一个节点的票数已经大于等于max(quorum,num(sentinels)/2+1),那么它将成为领导者。
-
如果此过程没有选举出领导者,将进入下一次选举。
3.5、故障转移
领导者选举出的Sentinel节点负责故障转移,具体步骤如下:
- 在从节点列表中选出一个节点作为新的主节点,方法如下:
-
过滤:"不健康"(主观下线、断线)、5秒内没有回复过Sentinel节点ping响应,与主节点失联超过down-after-milliseconds*10秒。
-
选择slave-priority(从优先级)最高的从节点列表,如果存在则返回,不存在则继续。
-
选择复制偏移量最大的从节点
-
选择runid最小的从节点
-
领导者节点会对第一步选出来的从节点执行slaveof no one命令,使其成为新主
-
领导者节点会向剩余的从节点发送命令,让他们成为新主的从节点
-
Sentinel节点集合会将原来的主节点更新为从节点并保持对其关注,当其恢复后命令它去复制新的主节点。
四、Sentinel集群部署
4.1、案例环境
系统 IP地址 主机名 端口 Redis角色
CentOS 7.9 192.168.115.111 redis 6379 master
CentOS 7.9 192.168.115.111 redis 6380 slave1
CentOS 7.9 192.168.115.111 redis 6381 slave2
CentOS 7.9 192.168.115.111 redis 26379 Sentinel
CentOS 7.9 192.168.115.111 redis 26380 Sentinel
CentOS 7.9 192.168.115.111 redis 26381 Sentinel
