Redis(7):哨兵机制

一、哨兵机制的简介

1.哨兵的功能和特性

        哨兵(sentinel),是redis集群架构中非常重要的一个组件,它主要的功能和特性如下:

(1)集群监控,负责监控redis master和slave进程是否正常工作。

(2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员。

(3)故障转移,如果master node挂掉了,会自动转移到slave node上。

(4)配置中心,如果故障转移发生了,通知client客户端新的master地址。

(5)哨兵本身也是分布式的,哨兵以集群的方式来相互协作。

(6)要进行故障转移时会涉及到分布式选举,当大部分哨兵节点都同意时才能进行。

(7)当部分哨兵节点不能正常工作时,哨兵集群还是能够正常工作。

2.哨兵的几个特点

(1)哨兵集群必须要部署两个以上节点,来保证哨兵的健壮性

        说到这个特点,我们就要说到两个参数,第一个是quorum,quorum是我们可以给哨兵集群配置的一个参数,它的作用是:当master节点宕机的时候需要有至少quorum个哨兵节点认为mater宕机才能进行后续的操作,比如主备切换、故障转移,这个时候还需要一个参数majority来判断是否可以进行故障转移,需要有大多数哨兵节点正常工作来同同意这次故障转移,即正常工作的哨兵节点数要大于majority,majority有一个通用的规则:2个哨兵节点的majority为2,3个哨兵节点的majority为2,4个哨兵节点的majority为2,5个哨兵节点的majority为3,以此类推。如果一个master节点宕机了,同时他的哨兵进程同时挂掉了,那么现在正常运行的哨兵节点数目为1,即使你把quorum设置为1,满足了quorum的条件,但是是不能满足正常运行的哨兵节点大于majority,也就是2,所以是不能保证能够进行故障转移的。

(2)哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性

       第一种情况: maser节点和slave节点之间的数据传输不是同步的,是异步的,当客户端往master中写数据的时,master异步的发送给slave节点,这当中会存在一定的延迟,当master节点挂掉的时候是不能保证这一小部分数据会及时的发送给slave节点。


Redis(7):哨兵机制_第1张图片
异步复制造成的数据丢失

        第二种情况:当master节点与slave节点间发生网络故障,导致无法与slave节点通讯,产生网络分区。这时,老的master节点并没有视为宕机,仍然在不停的写数据。此时这个slave节点如果被选举为新的master节点,这样就会发生“集群脑裂”,客户端程序还是会源源不断地将数据写入老的master节点,新的master节点却没有接收到新的数据,当网络恢复正常,老的master节点降为slave节点的时候,会立即执行全量的主从复制,那么故障之后的数据就会丢失。


Redis(7):哨兵机制_第2张图片
集群脑裂导致的数据丢失问题

(3)经典的三节点哨兵集群

        现在我们有一主两从的这样一个redis 集群,每个redis节点有一个哨兵,我们设置quorum为2,那么当master节点宕机的话,此时三个哨兵还剩下两个,剩下的两个slave节点一致认为master宕机,此时三个哨兵节点的majority为2,剩下还有2个正常运行的哨兵节点,那么就可以选举出新的master节点进行故障转移。

3.数据丢失的问题如何避免

        异步复制数据丢失,集群脑裂数据丢失的问题我们可以通过设置两个参数来减少数据丢失:

        min-slaves-to-write 1

        min-slaves-max-lag 10

        上面两个参数表达的意思为:要求至少有1个slave,数据复制和同步的延迟不能超过10秒。也就是说,如果所有的slave节点都落后于master节点10秒钟的数据,那么master节点就不会再接受任何请求了。

(1)减少异步复制的数据丢失

        有了min-slaves-max-lag这个配置,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内,最多也就丢失10秒的数据。

(2)减少脑裂的数据丢失

        如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求。这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失。上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求。因此在脑裂场景下,最多就丢失10秒的数据。

(3)当master不接受请求之后该如何处理

        当master不接受写请求之后,我们需要给client做降级,让它直接把数据写到本地磁盘里,让client自己处理这些数据,做相应的降级和限流,减慢数据涌入的速度。或者将数据写入一个消息队列,每隔一段时间取一次,尝试将数据重新写入到redis中。

4.redis的底层核心原理

(1)sdown和odown的转换机制

        什么是sdown,sdown又称为主观宕机,即一个哨兵觉得master节点宕机,这就是sdown。odown又称为客观宕机,即现在有quorum个哨兵都认为master宕机了。判断sdown的条件就是:一个哨兵ping一个master,超过了is-master-down-after-milliseconds参数指定的毫秒数之后,就主观认为master宕机。sdown转换到odown的条件就是:如果一个哨兵在指定时间内收到了超过quorum个哨兵的认为该master节点宕机的信息,就转换成了odown。

(2)哨兵集群的自动发现机制

        哨兵互相之间的发现,是通过redis的pub/sub系统实现的,每个哨兵都会往__sentinel__:hello这个channel里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在。每隔两秒钟,每个哨兵都会往自己监控的某个master+slaves对应的__sentinel__:hello channel里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置。每个哨兵也会去监听自己监控的每个master+slaves对应的__sentinel__:hello channel,然后去感知到同样在监听这个master+slaves的其他哨兵的存在。每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步。

(3)slave配置的自动纠正

        哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据; 如果slave连接到了一个错误的master上,比如故障转移之后,那么哨兵会确保它们连接到正确的master上。

(4)slave->master选举算法

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

a.跟master断开连接的时长

b.slave优先级

c.复制offset

d.run id

        如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍(加上master宕机的时长),那么slave就被认为不适合选举为master。计算公式为:(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state。接下来会对slave进行排序:

a.按照slave优先级进行排序,slave priority越低,优先级就越高

b.如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高

c.如果上面两个条件都相同,那么选择一个run id比较小的那个slave

(5)quorum和majority

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

(6)configuration epoch

        哨兵会对一套redis master+slave进行监控,有相应的监控的配置,执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个版本号,每次切换的version号都必须是唯一的。如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的版本号。

(7)configuraiton传播

        哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub消息机制。这里之前的版本号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的版本号,其他的哨兵都是根据版本号的大小来更新自己的master配置的。

你可能感兴趣的:(Redis(7):哨兵机制)