Redis开发与运维读书笔记之九——哨兵

Redis 的主从复制模式下,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址,对于很多应用场景这种故障处理的方式是无法接受的。 Redis 2.8 开始正式提供了 Redis Sentinel (哨兵)架构来解决这个问题。

一、基本概念

名词

逻辑结构

物理结构

主节点( master

Redis 主服务 / 数据库

一个独立的 Redis 进程

从节点( slave

Redis 从服务 / 数据库

一个独立的 Redis 进程

Redis 数据节点

主节点和从节点

主节点和从节点的进程

Sentinel 节点

监控 Redis 数据节点

一个独立的 Sentinel 进程

Sentinel 节点集合

若干 Sentinel 节点的抽象集合

若干 Sentinel 节点进程

Redis Sentinel

Redis 高可用实现方案

Sentinel 节点集合和 Redis 数据节点进程

应用方

泛指一个或多个客户端

一个或多个客户端进程或者线程

Redis Sentinel Redis 的高可用实现方案,在实际的生产环境中,对提高整个系统的高可用性是非常有帮助的。

1 、主从复制的问题

Redis 的主从复制模式可以让主节点的数据改变同步给从节点,这样从节点就可以起到两个作用:第一,作为主节点的一个备份,一旦从节点出了故障不可达的情况,从节点可以作为后备“顶”上来,并且保证数据尽量不丢失(主从复制是最终一致性)。第二,从节点可以扩展主节点的读能力,一旦主节点不能支撑住大并发量的读操作,从节点可以在一定程度上帮助主节点分担读压力。

但是主从复制也带来了以下问题:

  • 主节点出现故障,需要手动将从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令其他从节点去复制新的从节点,整个过程都需要人工干预。
  • 主节点的写能力受到单机的限制。
  • 主节点的存储能力受到单机的限制。

其中第一个问题就是 Redis 的高可用问题,第二、三个问题属于 Redis 的分布式问题。

2 、高可用

当主节点故障时, Redis Sentinel 能自动的完成故障发现和故障转移,并通知应用方,从而实现真正的高可用。使用 Redis Sentinel ,建议使用 2.8 以上版本。

Redis Sentinel 是一个分布式架构,其中包含若干个 Sentinel 节点和 Redis 数据节点, 每个 Sentinel 节点会对数据节点和其余 Sentinel 节点进行监控,当它发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,它还会和其他 Sentinel 节点进行“协商”,当大多数 Sentinel 节点都认为主节点不可达时,它们会选举出一个 Sentinel 节点来完成自动故障转移的工作,同时会将这个变化实时通知给 Redis 应用方。 整个过程完全是自动的,不需要人工来介入,所以这套方案很有效地解决了 Redis 的高可用问题。

注意:这里的分布式是指: Redis 数据节点、 Sentinel 节点集合、客户端分部在多个物理节点的架构,不要与 Redis Cluster 分布式混淆。

下面以一个主节点、 2 个从节点、 3 Sentinel 节点组成的 Redis Sentinel 为例子进行说明,拓扑结构如下图所示:

整个故障转移的处理逻辑有下面 4 个步骤:

1 )主节点出现故障,此时两个从节点与主节点失去连接,主从复制失败。

2 )每个 Sentinel 节点通过定期监控发现主节点出现了故障。

3 )多个 Sentinel 节点对主节点的故障达成一致,选举出 sentinel-3 节点作为领导者负责故障转移。

4 )如下图所示, Sentinel 领导者节点执行了故障转移,整个过程是自动化完成的。

5 )故障转移后整个 Redis Sentinel 的拓扑结构如下图所示:

通过上面介绍的 Redis Sentinel 逻辑架构以及故障转移的过程,可以看出 Redis Sentinel 具有以下几个功能:

  • 监控: Sentinel 节点会定期检测 Redis 数据节点、其余 Sentinel 节点是否可达。
  • 通知: Sentinel 节点会将故障转移的结果通知给应用方。
  • 主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系。
  • 配置提供者:在 Redis Sentinel 结构中,客户端在初始化的时候连接的是 Sentinel 节点集合,从中获取主节点信息。

Redis Sentinel 包含了若干个 Sentinel 节点,这样做带来了两个好处:

  • 对于节点的故障判断是由多个 Sentinel 节点共同完成的,这样可以有效地防止误判。
  • Sentinel 节点集合是由若干个 Sentinel 节点组成的,这样即使个别 Sentinel 节点不可用,整个 Sentinel 节点集合依然是健壮的。

Sentinel 节点本身就是独立的 Redis 节点,只不过比较特殊,不存储数据,只支持部分命令》

3 、部署

Redis哨兵的部署大家可以参考这篇博文,我这边也是按照这个配置成功的.

https://www.cnblogs.com/jaycekon/p/6237562.html

 

4 、部署技巧

1 Sentinel 节点不应该部署在一台物理“机器”上。

这里特意强调物理机是因为一台物理机做成了若干虚拟机或者容器,它们虽然有不同的 ip 地址,但实际上都是同一台物理机,同一台物理机意味着这台机器有什么硬件故障,所有的虚拟机都会受到影响,为了实现 Sentinel 节点集合真正的高可用,请勿将 Sentinel 节点部署在同一台物理机器上。

2 )部署至少三个且奇数个的 Sentinel 节点

3 个以上是通过增加 Sentinel 节点的个数提高对故障判定的准确性,因为领导者选举至少一半加 1 个节点,奇数个节点可以在满足该条件的基础上节省一个节点。

3 )只有一套 Sentinel ,还是每个主节点配置一套 Sentinel

Sentinel 节点集合可以只监控一个主节点,也可以监控多个主节点,也就意味着部署拓扑可能是下图两种情况:

 

分析两种方案的优缺点:

方案一:一套 Sentinel ,降低了维护成本 ,这是优点也是缺点,如果这套 Sentinel 节点集合出现异常,可能会对多个 Redis 数据节点造成影响。另外如果监控的 Redis 数据节点较多,会造成 Sentinel 节点产生过多的网络连接,有一定影响。

方案二:这种方案的优点和缺点和上面是相反的,每个 Redis 主节点都有自己的 Sentinel 节点集合,会造成资源浪费,但是优点也很明显,每套 Redis Sentinel 都是彼此隔离的。

如果 Sentinel 节点集合监控的是同一个业务的多个主节点集合,使用方案一,否则一般建议采用方案二。

实现原理

下面介绍 Redis Sentinel 的基本实现原理,具体包含以下几个方面: Redis Sentinel 的三个定时任务、主观下线和客观下线、 Sentinel 领导者选举、故障转移。

1 、三个定时任务

一套合理的监控机制是 Sentinel 节点判定节点不可达的重要保证, Redis Sentinel 通过三个定时监控任务完成对各个节点的发现和监控:

1 )每隔 10 秒,每个 Sentinel 节点会向主节点和从节点发送 info 命令获取最新的拓扑结构,如下图所示:

例如下面就是在一个主节点上执行info replication的结果片段:

# Replication 
role:master 
connected_slaves:2 
slave0:ip=127.0.0.1,port=6380,state=online,offset=4917,lag=1 slave1:ip=127.0.0.1,port=6381,state=online,offset=4917,lag=1

Sentinel 节点通过对上述结果进行解析就可以找到相应的从节点。

这个定时任务的作用具体可以表现在三个方面:

  • 通过向主节点执行 info 命令,获取从节点的信息,这也是为什么 Sentinel 节点不需要显式配置监控从节点。
  • 当有新的从节点加入时都可以立刻感知出来。
  • 节点不可达或者故障转移后,可以通过 info 命令实时更新节点拓扑信息。

2 )每隔 2 秒,每个 Sentinel 节点会向 Redis 的数据节点的__sentinel__:hello频道上发送该 Sentinel 节点对于主节点的判断以及当前 Sentinel 节点的信息(如下图所示),同时每个 Sentinel 节点也会订阅该频道,来了解其他 Sentinel 节点以及它们对主节点的判断,所以这个定时任务可以完成以下两个工作:

  • 发现新的 Sentinel 节点:通过订阅主节点的__sentinel__:hello了解其他的 Sentinel 节点信息,如果是新加入的 Sentinel 节点,将该 Sentinel 节点信息保存起来,并与该 Sentinel 节点创建连接。
  • Sentinel 节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据。

 

Sentinel节点publish的消息格式如下:

    

 

3)每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确认这些节点当前是否可达。如下图所示。通过上面的定时任务,Sentinel节点对主节点、从节点、其余Sentinel节点都建立起连接,实现了对每个节点的监控,这个定时任务是节点失败判定的重要依据。

 

2 、主观下线和客观下线

1 )主观下线

前面介绍的第三个定时任务,每个 Sentinel 节点会每隔 1 秒对主节点、从节点、其他 Sentinel 节点发送 ping 命令做心跳检测,当这些节点超过 down-after-milliseconds 没有进行有效回复, Sentinel 节点就会对该节点做失败判定,这个行为叫主观下线。从字面意思也可以很容易看出主观下线是当前 Sentinel 节点的一家之言,存在误判的可能,如下图所示

2 )客观下线

Sentinel 主观下线的节点是主节点时,该 Sentinel 节点会通过sentinel ismaster-down-by-addr命令向其他 Sentinel 节点询问对该主节点的判断,当超过 个数, Sentinel 节点认为主节点确实有问题,这时该 Sentinel 节点会做出客观下线的决定,这样客观下线的含义是比较明显的了,也就是大部分 Sentinel 节点都对主节点的下线做了同意的判断,那么这个判定就是客观的,如下图所示:

从节点、 Sentinel 节点在主观下线后,没有后续的故障转移操作。

这里有必要对sentinel is-master-down-by-addr命令做一个介绍,它的使用方法如下:

sentinel is-master-down-by-addr

  • ip :主节点 IP
  • port :主节点端口。
  • current_epoch :当前配置纪元。
  • runid :此参数有两种类型,不同类型决定了此 API 作用的不同。

runid 等于“ * ”时,作用是 Sentinel 节点直接交换对主节点下线的判定。

runid 等于当前 Sentinel 节点的 runid 时,作用是当前 Sentinel 节点希望目标 Sentinel 节点同意自己成为领导的请求,有关 Sentinel 领导者选举,后面会进行介绍。

例如 sentinel-1 节点对主节点做主观下线后,会向其他 Sentinel 节点(假设 sentinel-2 sentinel-3 节点)发送该命令:

sentinel is-master-down-by-addr 127.0.0.1 6379 0 *

返回结果包含三个参数,如下所示:

  • down_state :目标 Sentinel 节点对于主节点的下线判断, 1 是下线, 0 是在线。
  • leader_runid :当 leader_runid 等于” * “时,代表返回结果是用来做主节点是否不可达,当 leader_runid 等于具体 runid ,代表目标节点同意 runid 成为领导者。
  • leader_epoch :领导者纪元

3 、领导者 Sentinel 节点选举

假如 Sentinel 节点对于主节点已经做了客观下线,那么是不是就可以立即进行故障转移了,当然不是,实际上故障转移的工作只需要一个 Sentinel 节点来完成即可,所以 Sentinel 节点之间会做一个领导者选举的工作,选出一个 Sentinel 节点作为领导者进行故障转移的工作。 Redis 使用了 Raft 算法实现领导者选举,因为 Raft 算法相对比较抽象和复杂,以及篇幅所限,所以这里给出一个 Redis Sentinel 进行领导者选举的大致思路:

1 )每个在线的 Sentinel 节点都有资格成为领导者,当它确认主节点主观下线时候,会向其他 Sentinel 节点发送sentinel is-master-down-by-addr命令,要求将自己设置为领导者。

2 )收到命令的 Sentinel 节点,如果没有同意过其他 Sentinel 节点的sentinel is-master-down-by-addr命令,将同意该请求,否则拒绝。

3 )如果该 Sentinel 节点发现自己的票数已经大于等于 max (quorum, num(sentinels)/2+),那么它将成为领导者。

4 )如果次过程没有选举出领导者,将进入下一次选举。

下图展示了一次领导者选举的大致过程:

1 s1 sentinel-1 )最先完成了客观下线,它会向 s2 sentinel-2 )和 s3 sentinel-3 )发送sentinel is-master-down-by-addr命令, s2 s3 同意选其为领导者。

2 s1 此时已经拿到了 2 张投票,满足了大于等于 max (quorum, num(sentinels)/2+1) =2 的条件,所以此时 s1 成为领导者。

由于每个 Sentinel 节点只有一票,所以当 s2 s3 索要投票时,只能获取一票,而 s3 由于最后完成主观下线,当 s3 s1 s2 索要投票时一条都得不到。

实际上 Redis Sentinel 实现会更简单一些,因为一旦有一个 Sentinel 节点获得了 max (quorum,num(sentinels)/2+1)得票数,其他 Sentinel 节点再去确认已经没有意义了,因为每个 Sentinel 节点只有一票,选举的过程非常快,基本上谁先完成客观下线,谁就是领导者。

有关 Raft 算法可以参考其 GitHub 主页 https://raft.github.io/

4 、故障转移

领导者选举出的 Sentinel 节点复制故障转移,具体步骤如下:

1 )在从节点中选出一个节点作为新的主节点,选择方法如下:

a )过滤:”不健康“(主观下线、断线)、 5 秒内没有回复过 Sentinel 节点 ping 响应、与主节点失联超过down-after-milliseconds*10秒。

b )选择 slave-priority (从节点优先级)最高的从节点列表,如果存在则返回,不存在则继续。

c )选择复制偏移量最大的从节点(复制的最完整),如果存在就返回,不存在则继续。

d )选择 runid 最小的从节点。

2 Sentinel 领导节点会对第一步选出来的从节点执行 slaveof no one 命令让其成为主节点。

3 Sentinel 领导节点会向剩余的从节点发送命令,让它们成为新主节点的从节点,复制规则和 parallel-syncs 参数有关。

4 Sentinel 节点集合会将原来的主节点更新为从节点,并保持着对其关注,当其恢复后命令它去复制新的主节点。

小结:

1 Redis Sentinel Redis 的高可用实现方案:故障发现、故障自动转移、配置中心、客户端通知。

2 Redis Sentinel Redis2.8 版本开始才正式生产可用,之前版本生成不可用。

3 )尽可能在不同物理机上部署 Redis Sentinel 所有节点。

4 Redis Sentinel 中的 Sentinel 节点个数应该为大于等于 3 且最好为奇数。

5 Redis Sentinel 中的数据节点与普通节点没有区别。

6 )客户端初始化时连接的是 Sentinel 节点集合,不再是具体的 Redis 节点,但 Sentinel 只是配置中心而不是代理。

7 Redis Sentinel 通过三个定时任务实现了 Sentinel 节点对于主节点、从节点、其余 Sentinel 节点的监控。

8 Redis Sentinel 在对节点做失败判定时分为主观下线和客观下线。

 

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇