Redis的哨兵模式Sentinel

目录

Sentinel简介

经典的哨兵集群与模型功能

部署

部署主从节点

部署哨兵节点

演示故障转移

部署总结

客户端访问哨兵系统

代码示例

客户端原理

客户端访问哨兵系统总结

哨兵节点支持的命令

哨兵基本原理

配置与实践建议

配置

实践建议

启动井初始化Sentinel

初始化服务器

使用Sentinel专用代码

初始化Sentinel状态

初始化Sentinel状态的masters属性

创建连向主服务器的网络连接

获取主服务器信息

获取从服务器信息

向主服务器和从服务器发送信息

接收来自主服务器和从服务器的频道信息

更新sentinels字典

创建连向其他Sentinel的命令连接

Sentinel之间不会创建订阅连接

检测主观下线状态

主观下线时长选项的作用范围

多个Sentinel设置的主观下线时长可能不同

检查客观下线状态

发送SENTINEL is-master-down-by-addr命令

接收SENTINEL is-master-down-by-addr命令

接收SENTINEL is-master-down-by-addr命令的回复

客观下线状态的判断条件

不同Sentinel判断客观下线的条件可能不同

选举领头Sentinel

故障转移

选出新的主服务器

修改从服务器的复制目标

将旧的主服务器变为从服务器

主从复制的和故障转移的过程中的数据丢失

重点回顾


Sentinel简介

Sentinel (哨岗、哨兵)是Redis的高可用性(high availability)解决方案:由一个或多个 Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器, 并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替 已下线的主服务器继续处理命令请求。

Redis 支持主从同步,提供 Cluster 集群部署模式,通过 Sentinel哨兵来监控 Redis 主服务器的状态。当主挂掉时,在从节点中根据一定策略选出新主,并调整其他从 slaveof 到新主。

哨兵的核心功能是主节点的自动故障转移。下面是Redis官方文档对于哨兵功能的描述:

监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。

自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。

配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。

通知(Notification):哨兵可以将故障转移的结果发送给客户端。

其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置提供者和通知功能,则需要在与客户端的交互中才能体现。

这里对“客户端”一词在文章中的用法做一个说明:在前面的文章中,只要通过API访问redis服务器,都会称作客户端,包括redis-cli、Java客户端Jedis等;为了便于区分说明,本文中的客户端并不包括redis-cli,而是比redis-cli更加复杂:redis-cli使用的是redis提供的底层接口,而客户端则对这些接口、功能进行了封装,以便充分利用哨兵的配置提供者和通知功能。

选主的策略简单来说有三个

  • slave 的 priority 设置的越低,优先级越高;

  • 同等情况下,slave 复制的数据越多优先级越高;

  • 相同的条件下 runid 越小越容易被选中。

在 Redis 集群中,sentinel 也会进行多实例部署,sentinel 之间通过 Raft 协议来保证自身的高可用。

Redis Cluster 使用分片机制,在内部分为 16384 个 slot 插槽,分布在所有 master 节点上,每个 master 节点负责一部分 slot。数据操作时按 key 做 CRC16 来计算在哪个 slot,由哪个 master 进行处理。数据的冗余是通过 slave 节点来保障。

图展示了一个Sentinel系统监视服务器的例子,其中:

用双环图案表示的是当前的主服务器server1。

用单环图案表示的是主服务 器的三个从服务器server2、server3以及server4。

server2、server3、server4三个从服务器正在复制主服务器 server1, 而Sentinel系统则 在监视所有四个服务器。

假设这时,主服务器server1进 入下线状态,那么从服务器server2、 server3、server4对主服务器的复制 操作将被中止,并且Sentinel系统会察觉 到server1己下线,如图所示(下 线的服务器用虚线表示)。

当server1的下线时长超过用户设定的下线时长上限时,Sentinel系统就会对 server1执行故障转移操作:

首先,Sentinel系统会挑选server1属下的其中一个从服务器,井将这个被选中的 从服务器升级为新的主服务器。

之后,Sentinel系统会向server1属下的所有从服务器发送新的复制指令,让它们 成为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障 转移操作执行完毕。

另外,Sentinel还会继续监视已下线的server1, 并在它重新上线时,将它设置为 新的主服务器的从服务器。

举个例子,图展示了Sentinel系统将server2升级为新的主服务器,并让服务器 server3和server4成为server2的从服务器的过程。

之后,如果server1重新上线的话,它将被Sentinel系统降级为server2的从服务 器,如图所示。

经典的哨兵集群与模型功能

哨兵必须用三个实例去保证自己的健壮性的,哨兵+主从并不能保证数据不丢失,但是可以保证集群的高可用

为啥必须要三个实例呢?我们先看看两个哨兵会咋样。

master宕机了 s1和s2两个哨兵只要有一个认为你宕机了就切换了,并且会选举出一个哨兵去执行故障,但是这个时候也需要大多数哨兵都是运行的。

那这样有啥问题呢?M1宕机了,S1没挂那其实是OK的,但是整个机器都挂了呢?哨兵就只剩下S2个裸屌了,没有哨兵去允许故障转移了,虽然另外一个机器上还有R1,但是故障转移就是不执行。

经典的哨兵集群是这样的:

M1所在的机器挂了,哨兵还有两个,两个人一看他不是挂了嘛,那我们就选举一个出来执行故障转移不就好了。

它由两部分组成,哨兵节点和数据节点:

哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据。

数据节点:主节点和从节点都是数据节点。

部署

这一部分将部署一个简单的哨兵系统,包含1个主节点、2个从节点和3个哨兵节点。方便起见:所有这些节点都部署在一台机器上(局域网IP:192.168.92.128),使用端口号区分;节点的配置尽可能简化。


部署主从节点

哨兵系统中的主从节点,与普通的主从节点配置是一样的,并不需要做任何额外配置。下面分别是主节点(port=6379)和2个从节点(port=6380/6381)的配置文件,配置都比较简单,不再详述。

#redis-6379.conf

port 6379

daemonize yes

logfile "6379.log"

dbfilename "dump-6379.rdb"



#redis-6380.conf

port 6380

daemonize yes

logfile "6380.log"

dbfilename "dump-6380.rdb"

slaveof 192.168.92.128 6379



#redis-6381.conf

port 6381

daemonize yes

logfile "6381.log"

dbfilename "dump-6381.rdb"

slaveof 192.168.92.128 6379

配置完成后,依次启动主节点和从节点:

redis-server redis-6379.conf

redis-server redis-6380.conf

redis-server redis-6381.conf

节点启动后,连接主节点查看主从状态是否正常,如下图所示:


部署哨兵节点

哨兵节点本质上是特殊的Redis节点。

3个哨兵节点的配置几乎是完全一样的,主要区别在于端口号的不同(26379/26380/26381),下面以26379节点为例介绍节点的配置和启动方式;配置部分尽量简化,更多配置会在后面介绍。

#sentinel-26379.conf

port 26379

daemonize yes

logfile "26379.log"

sentinel monitor mymaster 192.168.92.128 6379 2

其中,sentinel monitor mymaster 192.168.92.128 6379 2 配置的含义是:该哨兵节点监控192.168.92.128:6379这个主节点,该主节点的名称是mymaster,最后的2的含义与主节点的故障判定有关:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移。

哨兵节点的启动有两种方式,二者作用是完全相同的:

redis-sentinel sentinel-26379.conf

redis-server sentinel-26379.conf --sentinel

按照上述方式配置和启动之后,整个哨兵系统就启动完毕了。可以通过redis-cli连接哨兵节点进行验证,如下图所示:可以看出26379哨兵节点已经在监控mymaster主节点(即192.168.92.128:6379),并发现了其2个从节点和另外2个哨兵节点。

此时如果查看哨兵节点的配置文件,会发现一些变化,以26379为例:

其中,dir只是显式声明了数据和日志所在的目录(在哨兵语境下只有日志);known-slave和known-sentinel显示哨兵已经发现了从节点和其他哨兵;带有epoch的参数与配置纪元有关(配置纪元是一个从0开始的计数器,每进行一次领导者哨兵选举,都会+1;领导者哨兵选举是故障转移阶段的一个操作,在后文原理部分会介绍)。


演示故障转移

哨兵的4个作用中,配置提供者和通知需要客户端的配合,本文将在下一章介绍客户端访问哨兵系统的方法时详细介绍。这一小节将演示当主节点发生故障时,哨兵的监控和自动故障转移功能。

(1)首先,使用kill命令杀掉主节点:

(2)如果此时立即在哨兵节点中使用info Sentinel命令查看,会发现主节点还没有切换过来,因为哨兵发现主节点故障并转移,需要一段时间。

(3)一段时间以后,再次在哨兵节点中执行info Sentinel查看,发现主节点已经切换成6380节点。

但是同时可以发现,哨兵节点认为新的主节点仍然有2个从节点,这是因为哨兵在将6380切换成主节点的同时,将6379节点置为其从节点;虽然6379从节点已经挂掉,但是由于哨兵并不会对从节点进行客观下线(其含义将在原理部分介绍),因此认为该从节点一直存在。当6379节点重新启动后,会自动变成6380节点的从节点。下面验证一下。

(4)重启6379节点:可以看到6379节点成为了6380节点的从节点。

(5)在故障转移阶段,哨兵和主从节点的配置文件都会被改写。

对于主从节点,主要是slaveof配置的变化:新的主节点没有了slaveof配置,其从节点则slaveof新的主节点。

对于哨兵节点,除了主从节点信息的变化,纪元(epoch)也会变化,下图中可以看到纪元相关的参数都+1了。


部署总结

哨兵系统的搭建过程,有几点需要注意:

(1)哨兵系统中的主从节点,与普通的主从节点并没有什么区别,故障发现和转移是由哨兵来控制和完成的。

(2)哨兵节点本质上是redis节点。

(3)每个哨兵节点,只需要配置监控主节点,便可以自动发现其他的哨兵节点和从节点。

(4)在哨兵节点启动和故障转移阶段,各个节点的配置文件会被重写(config rewrite)。

(5)本章的例子中,一个哨兵只监控了一个主节点;实际上,一个哨兵可以监控多个主节点,通过配置多条sentinel monitor即可实现。

客户端访问哨兵系统

上一小节演示了哨兵的两大作用:监控和自动故障转移,本小节则结合客户端演示哨兵的另外两个作用:配置提供者和通知。


代码示例

在介绍客户端的原理之前,先以Java客户端Jedis为例,演示一下使用方法:下面代码可以连接我们刚刚搭建的哨兵系统,并进行各种读写操作(代码中只演示如何连接哨兵,异常处理、资源关闭等未考虑)。

public static void testSentinel() throws Exception {

         String masterName = "mymaster";

         Set<String> sentinels = new HashSet<>();

         sentinels.add("192.168.92.128:26379");

         sentinels.add("192.168.92.128:26380");

         sentinels.add("192.168.92.128:26381");



         JedisSentinelPool pool = new JedisSentinelPool(masterName, sentinels); //初始化过程做了很多工作

         Jedis jedis = pool.getResource();

         jedis.set("key1", "value1");

         pool.close();

}


客户端原理

Jedis客户端对哨兵提供了很好的支持。如上述代码所示,我们只需要向Jedis提供哨兵节点集合和masterName,构造JedisSentinelPool对象;然后便可以像使用普通redis连接池一样来使用了:通过pool.getResource()获取连接,执行具体的命令。

在整个过程中,我们的代码不需要显式的指定主节点的地址,就可以连接到主节点;代码中对故障转移没有任何体现,就可以在哨兵完成故障转移后自动的切换主节点。之所以可以做到这一点,是因为在JedisSentinelPool的构造器中,进行了相关的工作;主要包括以下两点:

(1)遍历哨兵节点,获取主节点信息:遍历哨兵节点,通过其中一个哨兵节点+masterName获得主节点的信息;该功能是通过调用哨兵节点的sentinel get-master-addr-by-name命令实现,该命令示例如下:

一旦获得主节点信息,停止遍历(因此一般来说遍历到第一个哨兵节点,循环就停止了)。

(2)增加对哨兵的监听:这样当发生故障转移时,客户端便可以收到哨兵的通知,从而完成主节点的切换。具体做法是:利用redis提供的发布订阅功能,为每一个哨兵节点开启一个单独的线程,订阅哨兵节点的+switch-master频道,当收到消息时,重新初始化连接池。


客户端访问哨兵系统总结

通过客户端原理的介绍,可以加深对哨兵功能的理解:

(1)配置提供者:客户端可以通过哨兵节点+masterName获取主节点信息,在这里哨兵起到的作用就是配置提供者。

需要注意的是,哨兵只是配置提供者,而不是代理。二者的区别在于:如果是配置提供者,客户端在通过哨兵获得主节点信息后,会直接建立到主节点的连接,后续的请求(如set/get)会直接发向主节点;如果是代理,客户端的每一次请求都会发向哨兵,哨兵再通过主节点处理请求。

举一个例子可以很好的理解哨兵的作用是配置提供者,而不是代理。在前面部署的哨兵系统中,将哨兵节点的配置文件进行如下修改:

sentinel monitor mymaster 192.168.92.128 6379 2

改为

sentinel monitor mymaster 127.0.0.1 6379 2

然后,将前述客户端代码在局域网的另外一台机器上运行,会发现客户端无法连接主节点;这是因为哨兵作为配置提供者,客户端通过它查询到主节点的地址为127.0.0.1:6379,客户端会向127.0.0.1:6379建立redis连接,自然无法连接。如果哨兵是代理,这个问题就不会出现了。

(2)通知:哨兵节点在故障转移完成后,会将新的主节点信息发送给客户端,以便客户端及时切换主节点。 


哨兵节点支持的命令

哨兵节点作为运行在特殊模式下的redis节点,其支持的命令与普通的redis节点不同。在运维中,我们可以通过这些命令查询或修改哨兵系统;不过更重要的是,哨兵系统要实现故障发现、故障转移等各种功能,离不开哨兵节点之间的通信,而通信的很大一部分是通过哨兵节点支持的命令来实现的。下面介绍哨兵节点支持的主要命令。

(1)基础查询:通过这些命令,可以查询哨兵系统的拓扑结构、节点信息、配置信息等。

info sentinel:获取监控的所有主节点的基本信息

sentinel masters:获取监控的所有

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值