哨兵集群工作原理
「哨兵」部门并不是一个人,多个人共同组成一个「哨兵集群」,即使有一些「哨兵」被老王打死了,其他的「哨兵」依然可以共同协作完成监控、新掌门选举以及通知 slave 、master 以及每一个武林人士(客户端)。
在配置哨兵集群的时候,哨兵配置中只设置了监控的 master IP 和 port,并没有配置其他哨兵的连接信息。
sentinel monitor <master-name> <ip> <redis-port> <quorum>
哨兵之间是如何知道彼此的?如何知道 slave 并监控他们的?由哪一个「哨兵」执行主从切换呢?
带着这些问题,跟着「码哥字节」一起追本溯源,深入哨兵集群心脏。
pub/sub 实现哨兵间通信和发现 slave
65 哥:哨兵之间是如何知道彼此的?
哨兵之间可以相互通信约会搞事情,主要归功于 Redis 的 pub/sub
发布/订阅机制。
哨兵与 master 建立通信,利用 master 提供发布/订阅机制发布自己的信息,比如身高体重、是否单身、IP、端口……
master 有一个 __sentinel__:hello
的专用通道,用于哨兵之间发布和订阅消息。这就好比是 __sentinel__:hello
微信群,哨兵利用 master 建立的微信群发布自己的消息,同时关注其他哨兵发布的消息。
当多个哨兵实例都在主库上做了发布和订阅操作后,它们之间就能知道彼此的 IP 地址和端口,从而相互发现建立连接。
Redis 通过频道的方式对消息进行分别管理,这里的频道其实就是不同的微信群。比如“码哥字节读者技术群”就是专门分享技术的群。朋友们可以关注公众号,后台回复“加群”,一起成长。
65 哥:哨兵之间虽然建立连接了,但是还需要和 slave 建立连接,不然没法监控他们呀,如何知道 slave 并监控他们的?
的确,哨兵之间建立连接形成集群还不够,还需要跟 slave 建立连接,不然没法监控他们,无法对主从库进行心跳判断。
除此之外,如果发生了主从切换也得通知 slave 重新跟新 master 建立连接执行数据同步。关于主从架构数据同步原理可移步《Redis 高可用篇:你管这叫主从架构数据一致性同步》。
关键还是利用 master 来实现,哨兵向 master 发送 INFO
命令, master 掌门自然是知道自己门下所有的 salve 小弟的。所以 master 接收到命令后,便将 slave 列表告诉哨兵。
哨兵根据 master 响应的 slave 名单信息与每一个 salve 建立连接,并且根据这个连接持续监控哨兵。
如图所示,哨兵 2 向 Master 发送 INFO
命令,Master 就把 slave 列表返回给哨兵 2,哨兵 2 便根据 slave 列表连接信息与每一个 slave 建立连接,并基于此连接实现持续监控。
剩下的哨兵也同理基于此实现监控。
选择哨兵执行主从切换
65 哥:master 嗝屁了以后,哨兵这么多,那到底让哪一个哨兵来执行新 master 切换呢?
这个跟哨兵判断 master “客观下线”类似,也是通过投票的方式选出来的。
任何一个哨兵判断 master “主观下线”后,就会给其他哨兵基友发送 is-master-down-by-addr
命令,好基友则根据自己跟 master 之间的连接状况分别响应 Y
或者 N
,Y
表示赞成票, N
就是反对。
如果某个哨兵获得了大多数哨兵的“赞成票”之后,就可以标记 master 为 “客观下线”,赞成票数是通过哨兵配置文件中的 quorum 配置项设定。
sentinel monitor <master-name> <ip> <redis-port> <quorum>
比如一共 3 个哨兵组成集群,那么 quorum 就可以配置成 2,当一个哨兵获得了 2 张赞成票,就可以标记 master “客观下线”,当然这个票包含自己的那一票。
获得多数赞成票的哨兵可以向其他哨兵发送命令,申明自己想要执行主从切换。并让其他哨兵进行投票,投票过程就叫做 “Leader 选举”。
想要成为 “Leader”没那么简单,得有两把刷子。需要满足以下条件:
- 获得其他哨兵基友过半的赞成票;
- 赞成票的数量还要大于等于配置文件的 quorum 的值。
如果哨兵集群有 2 个实例,此时,一个哨兵要想成为 Leader,必须获得 2 票,而不是 1 票。所以,如果有个哨兵挂掉了,那么,此时的集群是无法进行主从库切换的。因此,通常我们至少会配置 3 个哨兵实例。
这也是为啥哨兵集群部署成单数的原因,双数的话多余浪费。
选举流程如下图所示:
通过 pub/sub 实现客户端事件通知
65 哥:新 master 选出来了,要怎么公示天下呢?
当然是召开新闻发布会呀,邀请消息相关类型的媒体报道传播,感兴趣的人自然就去关注订阅相关事件,并根据事件做出行动。
在 Redis 也是类似,通过 pub/sub 机制发布不同事件,让客户端在这里订阅消息。客户端可以订阅哨兵的消息,哨兵提供的消息订阅频道有很多,不同频道包含了主从库切换过程中的不同关键事件。
也就是在不同的“微信群”发布不同的事件,让对该事件感兴趣的人进群即可。
master 下线事件
- +sdown:进入“主观下线”状态;
- -sdown:退出“主观下线”状态;
- +odown:进入“客观下线”状态;
- -odown:退出“客观下线”状态;
slave 重新配置事件
- +slave-reconf-sent:哨兵发送 replicaof 命令重新配置从库;
- +slave-reconf-inprog:slave 配置了新 master,但是尚未进行同步;
- +slave-reconf-done:slave 配置了新 master,并与新 master 完成了数据同步;
新主库切换
+switch-master:master 地址发生了变化。
知道了这些频道之后,就可以让客户端从哨兵这里订阅消息了。客户端读取哨兵的配置文件后,可以获得哨兵的地址和端口,和哨兵建立网络连接。
然后,我们可以在客户端执行订阅命令,来获取不同的事件消息。
举个栗子:如下指令订阅“所有实例进入客观下线状态的事件”
SUBSCRIBE +odown
注意事项与配置说明
发现了没,Redis 的 pub/sub 发布订阅机制尤其重要,有了 pub/sub 机制,哨兵和哨兵之间、哨兵和从库之间、哨兵和客户端之间就都能建立起连接了,各种事件的发布也是通过这个机制实现。
down-after-milliseconds
Sentinel 配置文件中的 down-after-milliseconds 选项指定了 Sentinel 判断实例进入主观下线所需的时间长度:如果一个实例在 down-after-milliseconds 毫秒内,连续向 Sentinel 返回无效回复,那么 Sentinel 会修改这个实例所对应数据,以此来表示这个实例已经进入主观下线状态。
要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds。因为这个值在不同的哨兵实例上配置不一致,导致哨兵集群一直没有对有故障的主库形成共识,也就没有及时切换主库,最终的结果就是集群服务不稳定。
down-after-milliseconds * 10
down-after-milliseconds 是我们认定主从库断连的最大连接超时时间。如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,我们就可以认为主从节点断连了。如果发生断连的次数超过了 10 次,就说明这个从库的网络状况不好,不适合作为新主库。
总结
哨兵主要任务
Redis 哨兵机制是实现 Redis 不间断服务的高可用手段之一。主从架构集群的数据同步,是数据可靠的基础保障;主库宕机,自动执行主从切换是服务不间断的关键支撑。
Redis 哨兵机制实现了主从库的自动切换,再也不怕跟女盆友么么哒的时候 master 宕机了:
- 监控 master 与 slave 运行状态,判断是否客观下线;
- master 客观下线后,选择一个 slave 切换成 master;
- 通知 slave 和客户端新 master 信息。
哨兵集群原理
为了避免单个哨兵故障后无法进行主从切换,以及为了减少误判率,又引入了哨兵集群;哨兵集群又需要有一些机制来支撑它的正常运行:
- 基于 pub/sub 机制实现哨兵集群之间的通信;
- 基于 INFO 命令获取 slave 列表,帮助 哨兵与 slave 建立连接;
- 通过哨兵的 pub/sub,实现了与客户端和哨兵之间的事件通知。
主从切换,并不是随意选择一个哨兵就可以执行,而是通过投票仲裁,选择一个 Leader,由这个 Leader 负责主从切换。