Redis哨兵(Sentinel)模式

Redis哨兵(Sentinel)模式

前面我们讲解了redis的主从复制原理及配置。假设一种场景,我们的master服务器宕机了,只有去手动的切换slave为master服务器,需要人工干预,还会造成一段时间内服务不可用。那我们可以考虑redis的哨兵模式(Sentinel)。

什么是哨兵模式?

Redis哨兵(Sentinel)模式
首先要从redis的主从模式说起,redis的主从模式就是把上图的所有的哨兵去掉,就变成了主从模式,主从模式是主节点负责写请求,然后异步的同步给从节点,然后从节点负责读请求,所以在主从架构中redis每个节点保存的数据是相同的,只是数据的同步可能会有一点延迟,那考虑到高可用性,如果主节点挂了,是没有一个自动选主的机制的,需要人工来指定一个节点为主节点,然后再恢复成主从结构,所以其实也是不能做到高可用。
  为了解决主从模式不能高可用的问题,就发明了哨兵模式,所谓的哨兵模式,就是在原来的主从架构的基础上,又搞了一个集群,哨兵集群,这个集群会监控redis集群的主节点和从节点的状态,如果发现主节点挂了,就会重新在从节点中选出来一个作为主节点,从而做到高可用。
  那哨兵本身是一个集群,那这个集群之间是怎么通信的呢?哨兵模式既然可以监控redis集群,做到故障转移,哨兵集群又是怎么监控redis集群的呢?下面就分析这两个问题:

哨兵模式工作原理?

哨兵集群中的每个节点都会启动三个定时任务

  • 第一个定时任务: 每个sentinel节点每隔1s向所有的master、slaver、别的sentinel节点发送一个PING命令,作用:心跳检测。
  • 第二个定时任务: 每个sentinel每隔2s都会向master的sentinel:这个channel中发送自己掌握的集群信息和自己的一些信息(比如host,ip,run id),这个是利用redis的pub/sub(发布/订阅)功能,每个sentinel节点都会订阅这个channel,也就是说,每个sentinel节点都可以知道别的sentinel节点掌握的集群信息,作用:信息交换,了解别的sentinel的信息和他们对于主节点的判断。
  • 第三个定时任务: 每个sentinel节点每隔10s都会向master和slaver发送INFO命令,作用:发现最新的集群拓扑结构。

哨兵的工作方式

1、每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令。
2、如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。 
3、如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。 
4、当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 。
5、在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令 。
6、当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次 。
7、若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。 若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

主观下线

这个就是上面介绍的第一个定时任务做的事情,当sentinel节点向master发送一个PING命令,如果超过own-after-milliseconds(默认是30s,这个在sentinel的配置文件中可以自己配置)时间都没有收到有效回复,不好意思,我就认为你挂了,就是说为的主观下线(SDOWN),修改其flags状态为SRI_S_DOWN。

客观下线

要了解什么是客观下线要先了解几个重要参数

  1. quorum:如果要认为master客观下线,最少需要主观下线的sentinel节点个数,举例:如果5个sentinel节点,quorum=2,那只要2个sentinel主观下线,就可以判断master客观下线。
  2. majority:如果确定了master客观下线了,就要把其中一个slaver切换成master,做这个事情的并不是整个sentinel集群,而是sentinel集群会选出来一个sentinel节点来做,那怎么选出来的呢,下面会讲,但是有一个原则就是需要大多数节点都同意这个sentinel来做故障转移才可以,这个大多数节点就是这个参数。注意:如果sentinel节点个数5,quorum=2,majority=3,那就是3个节点同意就可以,如果quorum=5,majority=3,这时候majority=3就不管用了,需要5个节点都同意才可以。
  3. configuration epoch:这个其实就是version,每个新的master都要生成一个自己的configuration epoch,就是一个编号。

客观下线处理过程

  1. 每个主观下线的sentinel节点都会向其他sentinel节点发送 SENTINEL is-master-down-by-addr ip port current_epoch runid,(ip:主观下线的服务id,port:主观下线的服务端口,current_epoch:sentinel的纪元,runid:*,表示检测服务下线状态,如果是sentinel 运行id,表示用来选举领头sentinel(下面会讲选举领头sentinel))来询问其它sentinel是否同意服务下线。
  2. 每个sentinel收到命令之后,会根据发送过来的ip和端口检查自己判断的结果,如果自己也认为下线了,就会回复,回复包含三个参数:down_state(1表示已下线,0表示未下线),leader_runid(领头sentinal id),leader_epoch(领头sentinel纪元)。由于上面发送的runid参数是*,这里后两个参数先忽略。
  3. sentinel收到回复之后,根据quorum的值,判断达到这个值,如果大于或等于,就认为这个master客观下线

选择领头的sentinel

到现在为止,已经知道了master客观下线,那就需要一个sentinel来负责故障转移,那到底是哪个sentinel节点来做这件事呢?需要通过选举实现,具体的选举过程如下:

  1. 判断客观下线的sentinel节点向其他节点发送SENTINEL is-master-down-by-addr ip port current_epoch runid(注意:这时的runid是自己的run id,每个sentinel节点都有一个自己运行时id);
  2. 目标sentinel回复,由于这个选择领头sentinel的过程符合先到先得的原则,举例:sentinel1判断了客观下线,向sentinel2发送了第一步中的命令,sentinel2回复了sentinel1,说选你为领头,这时候sentinel3也向sentinel2发送第一步的命令,sentinel2会直接拒绝回复;
  3. 当sentinel发现选自己的节点个数超过majority(注意上面写的一种特殊情况quorum>majority)的个数的时候,自己就是领头节点;
  4. 如果没有一个sentinel达到了majority的数量,等一段时间,重新选举;

故障转移过程

通过上面的介绍,已经有了领头sentinel,下面就是要做故障转移了,故障转移的一个主要问题和选择领头sentinel问题差不多,到底要选择哪一个slaver节点来作为master呢?按照我们一般的常识,我们会认为哪个slaver中的数据和master中的数据相识度高哪个slaver就是master了,其实哨兵模式也差不多是这样判断的,不过还有别的判断条件,详细介绍如下:

在进行选择之前需要先剔除掉一些不满足条件的slaver,这些slaver不会作为变成master的备选

  • 剔除列表中已经下线的从服务
  • 剔除有5s没有回复sentinel的info命令的slaver
  • 剔除与已经下线的主服务连接断开时间超过 down-after-milliseconds*10+master宕机时长的slaver

选主过程

  1. 选择优先级最高的节点,通过sentinel配置文件中的replica-priority配置项,这个参数越小,表示优先级越高
  2. 如果第一步中的优先级相同,选择offset最大的,offset表示主节点向从节点同步数据的偏移量,越大表示同步的数据越多
  3. 如果第二步offset也相同,选择run id较小的
  4. 选出来master之后,领头的sentinel会向slave发送slaveof命令变成新的master的slaver
  5. 如果之前的master重新上线时,领头sentinel同样会给起发送slaveof命令,将其变成从节点

由于只有主节点负责写数据,如果有大量的写请求的时候,主节点负载太高,有挂掉的风险
解决办法:使用cluster模式(后面的章节会讲到)

Redis哨兵配置

接下来会配置3个哨兵和1主2从的Redis服务器来演示这个过程。

服务类型 是否主服务器 IP地址 端口
redis 127.0.0.1 6379
redis 127.0.0.1 6380
redis 127.0.0.1 6381
sentinel - 127.0.0.1 26379
sentinel - 127.0.0.1 26380
sentinel - 127.0.0.1 26381

上一章_点这里_我们配置了主从复制的redis.conf的文件夹,这里我们就不再讲述了:

# 使得Redis服务器可以跨网络访问
bind 0.0.0.0
# 设置密码
requirepass "123456"
# 指定主服务器,注意:有关slaveof的配置只是配置从服务器,主服务器不需要配置
slaveof 127.0.0.1 6379
# 主服务器密码,注意:有关slaveof的配置只是配置从服务器,主服务器不需要配置
masterauth 123456

上述内容主要是配置Redis服务器,从服务器比主服务器多一个slaveof的配置和密码。

配置3个哨兵,每个哨兵的配置都是一样的。在Redis安装目录下有一个sentinel.conf文件,copy一份进行修改:

# 禁止保护模式 关闭了保护模式,便于测试。
protected-mode no
# 配置监听的主服务器,这里sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,127.0.0.1代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作。
sentinel monitor mymaster 127.0.0.1 6379 2
# sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster 123456

启动redis服务器和sentinel服务

# 启动Redis服务器进程
./redis-server ./myredis/redis.conf
# 启动哨兵进程
./redis-sentinel ./myredis/sentinel.conf --sentinel

Redis哨兵(Sentinel)模式
可以看到,6379已经是6380、6381的master服务器。
Redis哨兵(Sentinel)模式
手动宕机主服务器6379,看看发生了什么变化,待续…

上一篇:Sentinel如何使用


下一篇:高可用Redis服务架构分析与搭建