Redis高可用-哨兵集群

0. 前言

除了主从复制,Redis另一种高可用方案是哨兵(sentinel)集群。

哨兵

sentinel,中文名是哨兵。哨兵是 Redis 集群架构中非常重要的一个组件,主要有以下功能:

  • 集群监控:负责监控 Redis master 和 slave 进程是否正常工作;
  • 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员;
  • 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上;
  • 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址

其核心功能是master节点的自动故障转移。
此外,哨兵用来保证Redis高可用,本身也是集群部署的,作为一个分布式系统,协同工作。
当然,会涉及到选举问题
故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行。
注意事项:

  • 哨兵至少需要 3 个实例,来保证自己的健壮性
  • 哨兵 + Redis 主从的部署架构,是不保证数据零丢失的,只能保证 Redis 集群的高可用性
  • 对于哨兵 + Redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练

Redis哨兵集群+主从架构

1.哨兵集群组建

哨兵集群如何组建?
基于Redis的Pub/Sub机制

例如:
在主从集群中,主库上有一个名为__sentinel__:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的。在下图中,哨兵 1 把自己的 IP(172.16.19.3)和端口(26579)发布到__sentinel__:hello频道上,哨兵 2 和 3 订阅了该频道。那么此时,哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号。然后,哨兵 2、3 可以和哨兵 1 建立网络连接。

通过这个方式,哨兵 2 和 3 也可以建立网络连接,这样一来,哨兵集群就形成了。它们相互间可以通过网络连接进行通信,比如说对主库有没有下线这件事儿进行判断和协商。

2.哨兵的监控功能

哨兵监控什么?如何监控?
由哨兵向主库发送 INFO 命令来完成的

哨兵 2 给主库发送 INFO 命令,主库接受到这个命令后,就会把从库列表返回给哨兵。接着,哨兵就可以根据从库列表中的连接信息,和每个从库建立连接,并在这个连接上持续地对从库进行监控。哨兵 1 和 3 可以通过相同的方法和从库建立连接。

3.master下线判定

首先,有两个“下线”概念:

  • 主观下线(sdown):任何一个哨兵都是可以监控探测,并作出master下线的判断
  • 客观下线(odown):由哨兵集群投票共同决定master是否下线

具体地:
如果某个哨兵(如下图中的哨兵2)ping一个 master,超过了 is-master-down-after-milliseconds 指定的毫秒数之后,就主观认为 master 宕机了,即“主观下线”,就会给其他哨兵发送 is-master-down-by-addr 命令;
如果这个哨兵在指定时间内,收到了 quorum数量的其它哨兵也认为那个 master 是 sdown 的(投票),那么就认为是 odown 了,即“客观下线”

如果赞成票数(这里是2)是大于等于哨兵配置文件中的 quorum 配置项(比如这里如果是quorum=2), 则可以判定主库客观下线了。

4.哨兵集群选举

判定master客观下线之后,由哪个哨兵节点执行主从切换?
通过选举。

为什么必然会出现选举/共识机制?

为了避免哨兵的单点情况发生,所以需要一个哨兵的分布式集群。作为分布式集群,必然涉及共识问题(即选举问题);同时故障的转移和通知都只需要一个主的哨兵节点就可以了。

哨兵的选举机制是什么样的?

哨兵的选举机制其实很简单,就是一个Raft选举算法: 选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举

任何一个想成为 Leader 的哨兵,要满足两个条件:

  • 第一,拿到半数以上的赞成票;
  • 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值

5.新master的选举

那么,可以开始主从切换了。选一个slave节点上位master

quorum 和 majority

每次一个哨兵要做主备切换,首先需要 quorum 数量的哨兵认为 odown,然后选举出一个哨兵来做切换,这个哨兵还需要得到 majority 哨兵的授权,才能正式执行切换。
如果 quorum < majority,比如 5 个哨兵,majority 就是 3,quorum 设置为 2,那么就 3 个哨兵授权就可以执行切换。
但是如果 quorum >= majority,那么必须 quorum 数量的哨兵都授权,比如 5 个哨兵,quorum 是 5,那么必须 5 个哨兵都同意授权,才能执行切换。

如果一个 master 被认为 odown 了,而且 majority 数量的哨兵都允许主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个 slave 来,会考虑 slave 的一些信息:

  • 跟 master 断开连接的时长
  • slave 优先级
  • 复制 offset
  • run id

过滤掉不合适的slave

如果一个 slave 跟 master 断开连接的时间已经超过了 down-after-milliseconds 的 10 倍,外加 master 宕机的时长,那么 slave 就被认为不适合选举为 master

对剩下的slave排序

  • 按照 slave 优先级进行排序,slave priority 越低,优先级就越高。
  • 如果 slave priority 相同,那么看 replica offset,哪个 slave 复制了越多的数据,offset 越靠后,优先级就越高。
  • 如果上面两个条件都相同,那么选择一个 run id 比较小的那个 slave。

6.故障转移

新的master选出来之后,就可以进行故障转移了

假设:判断主库客观下线了,同时选出sentinel 3是哨兵leader。
将slave-1脱离原从节点(PS: 5.0 中应该是replicaof no one),升级主节点, 将从节点slave-2指向新的主节点 通知客户端主节点已更换 将原主节点(oldMaster)变成从节点,指向新的主节点



  • 将slave-1脱离原从节点(PS: 5.0 中应该是replicaof no one),升级为主节点
  • 将从节点slave-2指向新的主节点
  • 通知客户端主节点已更换
  • 将原主节点(oldMaster)变成从节点,指向新的主节点

转移过后:

数据丢失问题?

异步复制导致的丢失

因为 master->slave 的复制是异步的,所以可能有部分数据还没复制到 slave,master 就宕机了,此时这部分数据就丢失了

脑裂导致的数据丢失

脑裂,也就是说,某个 master 所在机器突然脱离了正常的网络,跟其他 slave 机器不能连接,但是实际上 master 还运行着。此时哨兵可能就会认为 master 宕机了,然后开启选举,将其他 slave 切换成了 master。这个时候,**集群里就会有两个 master **,也就是所谓的脑裂。
此时虽然某个 slave 被切换成了 master,但是可能 client 还没来得及切换到新的 master,还继续向旧 master 写数据。因此旧 master 再次恢复的时候,会被作为一个 slave 挂到新的 master 上去,自己的数据会清空,重新从新的 master 复制数据。而新的 master 并没有后来 client 写入的数据,因此,这部分数据也就丢失了。

解决方案

min-slaves-to-write 1		// 要求至少有 1 个 slave
min-slaves-max-lag 10		// 数据复制和同步的延迟不能超过 10 秒

有了 min-slaves-max-lag 这个配置,就可以确保,一旦 slave 复制数据和 ack 延时太长,就认为可能 master 宕机后损失的数据太多了,那么就拒绝写请求,这样可以把 master 宕机时由于部分数据未同步到 slave 导致的数据丢失降低的可控范围内。
如果一个 master 出现了脑裂,跟其他 slave 丢了连接,那么上面两个配置可以确保,如果不能继续给指定数量的 slave 发送数据,而且 slave 超过 10 秒没有给自己 ack 消息,那么就直接拒绝客户端的写请求。因此在脑裂场景下,最多就丢失 10 秒的数据。

参考文章


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!