Redis Sentinel
一、主从复制面临的问题
Redis 的主从复制模式可以将主节点的数据改变同步给从节点,这样从节点就可以起到两个作用:
- 作为主节点的一个备份,一旦主节点出了故障不可达的情况,从节点可以作为后备“顶”上来,并且保证数据尽量不丢失(主从复制是最终一致性)。
- 从节点可以扩展主节点的读能力,一旦主节点不能支撑住大并发量的读操作,从节点可以在一定程度上帮助主节点分担读压力。
主从模式面临如下问题:
- 一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址,还需要命令其他从节点去复制新主节点,整个过程都需要人工干预。
- 主节点的写能力收到单机的限制。
- 主节点的存储能力收到单机的限制。
其中问题一的故障转移属于高可用性问题,而问题二和三则属于分布式问题可以采用集群模式解决。
二、高可用性
Redis 主从复制模式下,一旦主节点出现了故障不可达,需要人工干预进行故障转移,无论对于 Redis 的应用方还是运维方都带来了很大的不便。
- 对于应用方来说无法及时感知到主节点的变化,必然会造成一定的写数据丢失和读数据错误,甚至可能造成应用方服务不可用。
- 对于 Redis 的运维方来说,整个故障转移的过程是需要人工来介入的,故障转移实时性和准确性上都无法得到保障。
主从复制模式下主节点出现故障后,故障转移流程如下:
- 主节点故障后,客户端连接主节点失败,两个从节点与主节点连接失败造成复制中断。
- 选择一个从节点,对其执行
slaveof no one
命令,使其成为新的主节点。 - 从节点成为新主节点后,更新应用方的主节点信息,并重启应用方。
- 客户端命令另一个从节点去复制新的主节点。
- 原来的主节点恢复后,让其去复制新的主节点。
上述处理过程可以认为整个服务或者架构的设计不是高可用的,因为整个故障转移的过程需要人介入。考虑到这点,有些公司把上述流程自动化了,但是仍然存在如下问题:
- 第一,判断节点不可达的机制是否健全和标准。
- 第二,如果有多个从节点,怎样保证只有一个被晋升为主节点。
- 第三,通知客户端新的主节点机制是否足够健壮
三、使用 Redis Sentinel 达到高可用性
当主节点出现故障时,Redis Sentinel 能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用。
Redis Sentinel 是一个分布式架构(数据节点、Sentinel 节点、客户端分布在多个物理节点的架构),其中包含若干个 Sentinel 节点和 Redis 数据节点,每个 Sentinel 节点会对数据节点和其余 Sentinel 节点进行监控,当它发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,它还会和其他 Sentinel 节点进行“协商”,当大多数 Sentinel 节点都认为主节点不可达时,它们会选举出一个 Sentinel 节点来完成自动故障转移的工作,同时会将这个变化实时通知给 Redis 应用方。整个过程完全是自动的,不需要人工来介入,所以这套方案很有效地解决了 Redis 的高可用问题。
Sentinel 在进行故障转移时,处理步骤如下:
- 主节点出现故障,两个从节点与主节点失去连接。
- 每个 Sentinel 节点通过定期监控发现主节点出现了故障。
- 多个 Sentinel 节点对主节点的故障达成一致,从 Sentinel 节点集合中选举出一个节点作为领导者负责故障转移。
- Sentinel 领导者节点执行了故障转移。故障转移过程与人工转移流程一致,不过是自动化完成的。
总结一下 Redis Sentinel 的功能:
- 监控:Sentinel 节点会定期检测 Redis 数据节点、其余 Sentinel 节点是否可达。
- 通知:Sentinel 节点会将故障转移的结果通知给应用方。
- 主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系。
- 配置提供者:在 Redis Sentinel 结构中,客户端在初始化的时候连接的是 Sentinel 节点集合,从中获取主节点信息。
Redis Sentinel 包含多个 Sentinel 节点,对于节点的故障判断是由多个 Sentinel 节点共同完成的,这样可以有效地防止误判。并且即使个别节点集合中的 Sentinel 节点不可用,整个 Sentinel 节点集合依然是健壮的。
Sentinel 节点本身就是独立的 Redis 节点,只不过它们有一些特殊,它们不存储数据,只支持部分命令
四、Sentinel 节点的配置
Sentinel 可用配置一览,Sentinel 的默认配置可以从 Redis 源码文件夹下的 sentinel.conf
中查看:
1 | port 26379 |
sentinel monitor redis-master 127.0.0.1 6379 2
中表示监控 127.0.0.1:6379
这个主节点,其中 2
表示判断主节点失败至少需要两个 Sentinel 节点同意。redis-master
是主节点的别名。
五、Redis Sentinel 实现原理
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 节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据。
- 发现新的 Sentinel 节点。通过订阅主节点的
每隔 1 秒,每个 Sentinel 节点会向主节点、从节点、其余 Sentinel 节点发送一条 ping 命令做一次心跳检测,来确认这些节点当前是否可达。通过该定时任务,Sentinel节点对主节点、从节点、其余Sentinel节点都建立起连接,实现了对每个节点的监控,这个定时任务是节点失败判定的重要依据。
2、主观下线和客观下线
上面提到的定时任务之一,每个 Sentinel 节点每隔 1 秒对主节点、从节点、其他 Sentinel 节点发送 ping
命令做心跳检测,当这些节点超过 down-after-milliseconds
没有进行有效回复,Sentinel 节点就会对该节点做失败判定。这个就叫做主观下线。主观下线为单个 Sentinel 节点自己的判断,未与其他 Sentinel 节点“沟通”。
当 Sentinel 主观下线的节点是主节点时,该 Sentinel 节点会通过 sentinel is-master-down-by-addr
命令向其他 Sentinel 节点询问对主节点的判断,当超过 <quorum>
个数,Sentinel 节点认为主节点确实有问题,这时该 Sentinel 节点会做出客观下线的决定。
从节点、Sentinel 节点在主观下线后,没有后续的故障转移操作。
3、领导者 Sentinel 节点选举
故障转移的工作只需要一个 Sentinel 节点来完成即可,所以 Sentinel 节点之间会做一个领导者选举的工作,选出一个 Sentinel 节点作为领导者进行故障转移的工作。
Redis 使用了 Raft 算法实现领导者选举,Redis Sentinel 进行领导者选举的大致流程如下:
- 每个在线的 Sentinel 节点都有资格成为领导者,当它确认主节点客观下线的时候,会向其他 Sentinel 节点发送
sentinel is-master-down-by-addr
命令,要求将自己设置为领导者。 - 收到命令的 Sentinel 节点,如果没有同意过其他 Sentinel 节点的
sentinel is-master-down-by-addr
命令,将同意该请求,否则拒绝。 - 如果该 Sentinel 节点发现自己的票数已经大于等于
max(quorum,num(sentinels)/2+1)
,那么它将成为领导者。 - 如果此过程没有选举出领导者,将进入下一次选举。
一旦有一个 Sentinel 节点获得了
max(quorum,num(sentinels)/2+1)
的票数,其他 Sentinel 节点再去确认已经没有意义了,因为每个 Sentinel 节点只有一票。
Sentinel 之间通过发送
RAFT
的投票协议消息来选举领导者。每个 Sentinel 节点都会给某一个请求它进行投票的 Sentinel 节点投票,但在整个选举过程中,每个 Sentinel 只能投一次票。通常情况下,第一个请求投票的 Sentinel 会获得同意。如果某个Sentinel
节点发现自己得到的票数已经超过半数且超过<quorum>
,那么它就成为领导者。如果这个过程中有多个Sentinel
成为领导者,那么将等待一段时间重新进行选择,直到有且只有一个Sentinel
节点成为领导者为止。
Raft 算法详情可查看 Raft Consensus Algorithm
4、故障转移
通过领导者选举出的 Sentinel 节点负责故障转移,具体步骤如下:
- 在从节点列表中选出一个节点作为新的主节点,选择方法如下:
- 过滤掉“不健康”(主观下线、断线)、5 秒内没有回复过 Sentinel 节点
ping
响应、与主节点失联超过down-after-milliseconds*10秒
的从节点。 - 选择从节点优先级最高(
replica-priority
数值最小)的从节点列表,如果存在则返回,不存在则继续。 - 选择复制偏移量最大的从节点(复制的最完整),如果存在则返回,不存在则继续。
- 选择
runid
最小的从节点。
- 过滤掉“不健康”(主观下线、断线)、5 秒内没有回复过 Sentinel 节点
- Sentinel 领导这节点会对选出的从节点执行
slave no one
命令,使其成为主节点。 - Sentinel 领导者节点会向剩余从节点发送命令,让他们成为新主节点的从节点,复制规则和
parallel-syncs
参数有关。 - Sentinel 节点集合会将原来的主节点更新为从节点,并保持对其的关注,当其恢复后命令它去复制新的主节点。
六、部署 Redis Sentinel 注意事项
生产环境中建议 Redis Sentinel 的所有节点应该分布在不同的物理机上。
部署至少三个且奇数个的 Sentinel 节点。
如果 Sentinel 节点集合监控的是同一个业务的多个主节点集合,那么可以使用一套 Sentinel,否则一般建议使用多套 Sentinel。
- 一套 Sentinel 指的是一个 Sentinel 节点集合监控多个主节点。
- 多套 Sentinel 指的是有多个 Redis 主节点,每一个主节点都使用单独的 Sentinel 节点集合进行监控。
副本优先级属性
replica-priority
的设置- 为硬件性能更强的从节点设置更高的优先级(
replica-priority
数值越小),确保故障转移后新主节点能高效处理请求。 - 弱某些节点因网络或资源限制不适合作为主节点,可将其
replica-priority
设置为 0 排除候选。
- 为硬件性能更强的从节点设置更高的优先级(
七、API 命令
1、sentinel is-master-down-by-addr
Sentinel 节点之间用来交换对主节点是否下线的判断,根据参数的不同,还可以作为 Sentinel 领导者选举的通信方式。
1 | sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid> |
ip
,主节点的 IPport
,主节点端口current_epoch
,当前配置的纪元runid
,取值不同作用不同,分别作用于主管下线和领导者选举。- 取
*
时,作用是 Sentinel 节点直接交换对主节点下线的判定。 - 值等于当前 Sentinel 节点的
runid
时,作用是当前 Sentinel 节点希望目标 Sentinel 节点同意自己成为领导者的请求。
- 取
该命令的返回结果包含三个参数,如下所示:
down_state
:目标 Sentinel 节点对于主节点的下线判断,1 是下线,0 是在线。leader_runid
:当leader_runid
等于*
时,代表返回结果是用来做主节点是否不可达,当leader_runid
等于具体的runid
,代表目标节点同意runid
成为领导者。leader_epoch
:领导者纪元。
2、sentinel monitor <master name> <ip> <port> <quorum>
此命令和配置文件中的含义完全一样,只不过是通过命令的形式来完成 Sentinel 节点对主节点的监控。
master name
,自定义主节点的名称标识,用于区分不同的 Redis 服务。ip
和port
,指定主节点的 IP 地址和端口号。quorum
,触发主节点客观下线所需的最小 Sentinel 同意数量。该配置只用来判断客观下线。
相关链接
OB links
[[Docker 中部署 Redis#四、哨兵模式]]
OB tags
#Redis #未完待续