哨兵机制

如果Redis主服务器挂了会怎样?

Redis提供了哨兵(Sentinel)机制供我们解决上面的情况。如果主服务器挂了,我们可以将从服务器升级为主服务器,等到旧的主服务器(挂掉的那个)重连上来,会将他(挂掉的那个)变成从服务器。这个过程叫做主备切换(故障转移)

在正常情况下,主从加哨兵机制是这样的:


主服务器挂了,主从复制操作就终止了,并且哨兵系统是可以察觉出主服务器挂了:


Redis提供哨兵机制可以选举一台从服务器变成主服务器:


如果主服务器重连了,会变成从服务器:


哨兵机制的细节

哨兵(Sentinel)机制主要用于实现Redis的高可用性,主要功能如下:

哨兵会不停的监控Redis主从服务器是否正常工作

如果某个Redis实例有故障,那么哨兵负责发送消息通知管理员

如果主服务器挂掉,会自动将某个从服务器提升为主服务器(包括配置都会修改)

Sentinel可以作为配置中心,能够提供当前主服务器的信息。

tips:Sentinel可以让我们的Redis实现高可用,Sentinel作为这么一个组件,自身也必然是高可用的(不可能是单点的)

启动和初始化Sentinel

Sentinel本质上只是一个运行在特殊模式下的Redis服务器。因为Sentinel做的事情和Redis服务器时不一样的,所以他们的初始化是有所区别的(如Sentinel初始化时不会再入AOF/RDB文件,因为Sentinel根本就不用数据库)

然后,在启动的时候会将普通的Redis服务器的代码替换成Sentinel专用代码。(所以Sentinel虽然作为Redis服务器,但是他不能执行Set等命令)

接着,初始化Sentinel的状态,并根据给定的配置文件初始化Sentinel监视的主服务器列表。


最后,Sentinel会创建两个连向主服务器的网络连接:

命令连接(发送和接收命令)

订阅连接(订阅主服务器的Sentinel:hello频道)


获取和更新信息

Sentinel通过主服务器发送INFO命令来获得主服务器属下所有从服务器的地址信息,并为这些从服务器创建响应的实例结构。


当发现有新的从服务器出现时,除了创建对应的从服务器实例结构,Sentinel还会创建命令连接和订阅连接。


在Sentinel运行的过程中,通过命令连接会以每两秒一次的频率向监视的主从服务器的sentinel:hello频道发送命令(主要发送Sentinel本身的信息,监听主从服务器的信息),并通过订阅连接接收sentinel:hello频道的信息

这样一来一回,我们就可以更新每个Sentinel实例结构的信息。

判断主服务器是否下线

判断主服务器是否下线有两种情况:

1. 主观下线:Sentinel会以每秒一次的频率向与它创建命令连接的实例(包括主从服务器和其他的Sentinel)发送PING命令,通过PING命令返回的信息判断实例是否在线。如果一个主服务器在down-after-millseconds毫秒连续向Sentinel发送无效回复,那么当前Sentinel就会主观认为该主服务器已经下线了。

2. 客观下线:当Sentinel将一个主服务器判定为主观下线后,为了确认该主服务器是否真的下线,他会同样监听该主服务器的Sentinel询问,看他们是否也认为该主服务器是否下线。如果足够多的Sentinel认为该主服务器是下线的,那么就判定该主服务器为客观下线,并对主服务器执行故障转移操作。

在多少毫秒内无效回复才认定主服务器是主观下线的,以及多少个Sentinel认为主服务器是下线的,才认定为客观下线。这都是可以配置的

选举领头Sentinel和故障转移

当一个主服务器认为客观下线以后,监视这个下线的主服务器的各种Sentinel会进行协商,选举出一个领头的Sentinel,领头的Sentinel会对下线的主服务器执行故障转移操作。

选举领头Sentinel的规则也比较多,总的来说就是先到先得

选举出领头的Sentinel之后,领头的Sentinel会对已经下线的主服务器执行故障转移操作,包括三个步骤:

1. 在已下线主服务器属下的从服务器中,挑选出一个转换为主服务器

2. 让已下线的主服务器属下的所有从服务器改为复制新的主服务器

3. 已下线的主服务器重新连接时,让他成为新的主服务器的从服务器

挑选一个从服务器作为主服务器也是有策略的,大概如下:

跟master断开连接的时长

slave优先级

复制offset

run id

即使这样,Redis还是会丢失数据的。

分两种情况:

异步复制导致的数据丢失:有部分数据还没有复制到从服务器上,主服务器就宕机了,此时这些部分数据就会丢失了

脑裂导致的数据丢失:有时候主服务器脱离了正常网络,跟其他从服务器不能连接。此时哨兵可能就会认为主服务器下线了(然后开启选举,将某个从服务器切换成了主服务器),但是实际上主服务器还运行着。这个时候,集群里就会有两个服务器(也就是所谓的脑裂),虽然某个从服务器被切换成了主服务器,但是可能客户端还没来得及切换到新的主服务器,客户端还继续向旧主服务器写数据。旧的服务器重新连接时,会作为从服务器复制新的主服务器(这意味着旧数据丢失)。

可以通过以下两个配置尽量减少数据丢失的可能:

min-slaves-to-write 1

min-slaves-max-lag 10