Sentinel(哨兵)

Sentinel(哨兵),第1张

    Redis主从复制模式下,一旦主节点(主服务器)由于故障不能提供服务,需要人工将节点晋升为主节点,同时还要通知应用方更新主节点的地址,然而应用方无法及时感知到主节点的变化,必然会造成一定的写数据丢失和读数据错误,所以这是在大多数情况是无法接受的。所以Redis提供了一种高可用的解决方法——哨兵

    Sentinel是Redis的高可用解决方案: 由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态下时,自动将下线主服务器属下的某个从服务器升级为主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。如果下线的主服务器重新连接上线的话,它会被Sentinel系统降级为新主服务器的从服务器。 而这些过程完全是自动的,不需要人工介。

    下面介绍Sentinel系统的具体工作过程。

    Sentinel只是一个运行在特殊模式下的Redis服务器,其本身就是独立的Redis节点,只不过它不存储数据,只支持部分命令。

    Sentinel会读入用户指定的配置文件,为每个要被监视的主服务器创建相应的实例结构保存在Sentinel状态(服务器初始化的一个sentinel结构,用于保存服务器中所有和Sentinel功能有关的状态)的masters属性中。并创建连向主服务器的网络连接,Sentinel将成为主服务器的客户端,并从命令回复中获取相关信息。

    对于每个被Sentinel监视的主服务器来说,Sentinel会创建两个连向主服务器的异步网络连接:

    1) 一个是命令连接,这个连接专门用于向主服务器的网络连接,并接受命令。

    2) 另一个是订阅连接,这个连接专门用于订阅主服务器的_sentinel_:hello频道。

  Sentinel默认每10秒一次的频率,通过命令连接向被 监视的主服务器发送 INFO 命令,并通过 INFO 命令的回复来获取主服务器以下的信息:

    (1) 服务器本身的信息,包括运行ID以及服务器的角色(role);

    (2) 主服务属下的所有从服务器信息,包括从服务器的IP地址,端口号。 根据这些IP和端口号,Sentinel无须用户提供从服务器的地址信息,就可以自动发现从服务器。

    Sentinel根据这些获取的信息对主服务的实例结构进行更新。

    对于上图,Sentinel将分别为3个从服务器创建各自的实例结构,并将这些实例结构保存主服务器实例结构的slaves属性里。

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

        在创建命令连接之后, Sentinel在默认情况下, 会以每10秒 一次的频率通过命令连接向从服务器发送 INFO 命令,并获取从服务器的回复信息,包括从服务器运行ID、从服务器的角色,主服务器的IP和端口、从服务的优先级等。根据这些信息对从服务器实例结构进行更新。

    在默认情况下,Sentinel会以每2秒一次的频率,通过命令连接向所有被监听的主服务器和从服务器的_sentinel_ hello频道发送一条消息。消息的信息包括Sentinel本身的信息和对主服务器判断的信息。

    当Sentinel与一个主服务器或者从服务器建立起订阅连接之后, Sentinel就会通过订阅连接, 向服务器发送以下命令:SUBSCRIBE _sentinel_:hello 。

    Sentinel对_sentinel_:hello频道的订阅会一直持续到Sentinel与服务器的连接断开为止。

    这也就是说, 对于每个与Sentinel连接的服务器, Sentinel既通过命令连接向服务器的 sentinel_:hello频道发送信息, 又通过订阅连接从服务器的 sentinel :hello 频道接收信息。

    对于监视同一个服务器的多个Sentinel 来说, 一个Sentinel发送的信息会被其他 Sentinel接收到, 这些信息会被用于更新其他Sentinel对发送信息Sentinel的认知 ,也会被用于更新其他Sentinel对被监视服务器的认知。

    举个例子, 假设现在有sentinel1、sentinel 2、sentinel 3三个Sentinel在监视同一个服务器, 那么当sentinel1向服务器的_sentinel_:hello频道发送一条信息时,所有订阅了_sentinel_:hello频道的Sentinel(包括sentinel1自己在内)都会收到这条信息。

    当一个Sentinel从_sentinel_:hello频道收到一条信息时,Sentinel会对这条信息进行分析,提取出信息中的Sentinel IP地址、端口号、Sentinel运行ID等参数,并作以下检查:

    **如果信息中记录的Sentinel运行ID和接收信息中Sentinel的运行ID 相同,说明这条信息是Sentinel自己发送的,Sentinel将丢弃这条信息,不做进一步处理。

    **如果信息中记录的Sentinel运行ID和接收信息的Sentinel的运行ID不相同,那么说明这条信息是监视同一个服务器的其他Sentinel发来的, 接收信息的Sentinel 将根据信息中的各个参数, 对相应主服务器的实例结构进行更新。

    这里的更新包括:主服务sentinels属性的更新和创建连向其他Sentinel命令连接

    (1)  Sentinel为主服务器创建的实例结构中的sentinels属性保存了除Sentinel本身之外,所有同样监视这个主服务器的其他Sentinel的资料。当一个Sentinel接收到其他Sentinel发来的信息时(我们称呼发送信息的Sentinel为源Sentinel, 接收信息的Sentinel为目标Sentinel),根据信息中提取出主服务器参数,目标Sentinel会在自己的Sentinel状态的masters字典中查找相应的主服务器实例结构, 然后根据提取出的Sentinel参数,检查主服务器实例结构的sentinels中,源Sentinel的实例结构是否存在:

    因为一个Sentinel可以通过分析接收到的频道信息来获取其他Sentinel的存在,并通过发送频道信息让其他Sentinel知道自己的存在,所以用户在使用Sentinel时不需要提供各个Sentinel的地址信息,监视同一个主服务器的多个Sentinel可以自动发现对方。

(2) 创建连向其他Sentinel命令连接

    当Sentinel通过频道信息发现一个新的Sentinel时, 它不仅会为新Sentinel在sentinels中创建相应的实例结构, 还会创建一个连向新Sentinel的命令连接, 而新Sentinel也同样会创建连向这个Sentinel的命令连接, 最终监视同一主服务器的多个Sentinel将形成相互连接的网络。

    在默认情况下,Sentinel会以 每秒一次 的频率向所有与它创建了命令的连接实例 (包括主服务器、从服务器、其他Sentinel在内),发送PING命令 ,并通过实例返回PING命令的回复判断实例是否在线,如果在规定的时间内,连续向Sentinel返回无效的回复(除了+PONG、-LOADING、-MASTERDOWN之外的回复),那么Sentinel会修改这个实例所对应的实例结构,在结构的flags属性中打开SRI_S_DOWN标识,以此来标识这个实例已经进入了 主观下线状态 。

    当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了, 它会向同样监视这一主服务器的其他Sentinel进行询问, 看它们是否也认为主服务器已经进人了下线状态(可以是主观下线或者客观下线)。 当Sentinel从其他Sentinel那里接收到足够数量的已下线判断之后, Sentinel就会将从服务器判定为客观下线, Sentinel会将主服务器实例结构flags属性的SRI_O_DOWN标识打开,标识主服务器已经进入了客观下线状态。

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

    选举领头Sentinel规则和方法:

      下面两幅图表示当三个Sentinel发现主服务器已经进入客观下线状态后,为了选举出领头Sentinel,三个Sentinel将再次向其他Sentinel发送SENTINEL is-master-down-by-addr命令要求其他Sentinel将自己设置为局部领头Sentinel。根据先到先得规则,如果某个Sentinel发送的命令比其他的快,并最终胜出领头Sentinel的选举,然后这个领头Sentinel就可以开始对服务器执行故障转移操作了。

    在选举产生出领头Sentinel之后,领头Sentinel将对已下线的主服务器执行故障转移操作,该操作包含以下三个步骤:

    (1) 选出新的主服务器

        故障转移的第一步就是在已下线主服务器属下的所有从服务器中挑选出一个状态良好、数据完成整的从服务器,然后向这个从服务器发送slave no one 命令,将这个从服务器装换为主服务器。

    下图展示在一次故障转移操作中,领头Sentinel向选中的从服务器server3发送 SLAVEOF no one 命令。

    在发送 SLAVEOF no one命令之后,领头 Sentinel会以每秒一次的频率(平时是每10秒一次),向被升级的从服服务发送INFO命令,并观察命令回复中角色(role)信息,当被升级的从服务器的role由原来的slave变为master时,领头Sentinel就知道被选中的从服务器顺利升级为主服务器了。

(2) 修改从服务器的复制目标

    当新的主服务器出现之后,领头Sentinel让已下线主服务器属下的所有从服务器去复制新的主服务器,这一动作可以通过向从服务器发送 SLAVE OF 命令来实现。

     (3) 将旧的主服务器变为从服务器

    故障转移操作最后要做的是, 将巳下线的主服务器设置为新的主服务器的从服务器。

    当serverl1重新上线时,Sentinel就会向它发送 SLAVEOF 命令,让它成为server3的从服务器。

    Redis的Sentinel实现主要包含以下几个方面: 三个定时任务、主观下线和客观下线检测、领头Sentinel的选举、故障转移。

  (1) 定时任务

  (2) 主观下线和客观下线检测

    客观下线:当Sentinel将一个主服务器判断为主观下线后,为了确认这个主服务是否真的下线了,他会向同样监视这个主服务器的所有其他Sentinel进行询问,看它们是否也认为主服务器是否进入下线状态,如果有足够多数量的Sentinel认为主服务器进入下线状态时,Sentinel就会将主服务器判定为客观下线状态。

  (3) 领头Sentinel的选举

    在主服务器被判定为客观下线后,Sentinel之间会根据一定的规则选出一个领头Sentinel,故障转移的工作就是这个领头Sentinel来完成的。

  (4) 故障转移

 注:本文参考《Redis设计与实现》,如发现错误,请指正!

主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。 这不是一种推荐的方式,更多时候,我们优先考虑 哨兵模式 。

一、哨兵模式概述

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是 哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

Redis哨兵

这里的哨兵有两个作用

通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。

当哨兵监测到master宕机,会自动将slave切换成master,然后通过 发布订阅模式 通知其他的从服务器,修改配置文件,让它们切换主机。

然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

用文字描述一下 故障切换(failover) 的过程。假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为 主观下线 。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为 客观下线 。这样对于客户端而言,一切都是透明的。

二、Redis配置哨兵模式

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

服务类型是否是主服务器IP地址端口

Redis是192.168.11.1286379

Redis否192.168.11.1296379

Redis否192.168.11.1306379

Sentinel-192.168.11.12826379

Sentinel-192.168.11.12926379

Sentinel-192.168.11.13026379

多哨兵监控Redis

首先配置Redis的主从服务器,修改redis.conf文件如下

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

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

上述关闭了保护模式,便于测试。

有了上述的修改,我们可以进入Redis的安装目录的src目录,通过下面的命令启动服务器和哨兵

注意启动的顺序。 首先是主机(192.168.11.128)的Redis服务进程,然后启动从机的服务进程,最后启动3个哨兵的服务进程。

三、Java中使用哨兵模式

    上面是通过Jedis进行使用的,同样也可以使用Spring进行配置RedisTemplate使用。

四、哨兵模式的其他配置项

        sentinel down-after-milliseconds配置项只是一个哨兵在超过规定时间依旧没有得到响应后,会自己认为主机不可用。对于其他哨兵而言,并不是这样认为。哨兵会记录这个消息,当拥有认为主观下线的哨兵达到sentinel monitor所配置的数量时,就会发起一次投票,进行failover,此时哨兵会重写Redis的哨兵配置文件,以适应新场景的需要。

Redis的Sentinel文档

概述:Redis的Sentinel系统用于管理多个Redis服务器,该系统执行以下三个任务:

如何使用?

启动Sentinel

    对于 redis-sentinel 程序,你可以用一下命令来启动Sentinel系统:

    对于 redis-server 程序,你可以用下面的命令来启动一个运行在Sentinel模式下的Redis服务器

    两种方式都可以启动一个sentinel实例,启动sentinel实例必须指定相应的配置文件,系统会使用配置文件来保存sentinel的当前状态,并在Sentinel重启时通过载入配置文件来进行状态还原。

    注意:如果启动Sentinel时没有指定相应的配置文件,或者指定的配置文件不可用(not writabel),那么Sentinel会拒绝启动。

    如何配置Sentinel?

    Redis 源码中包含了一个名为 sentinel.conf 的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。

运行一个 Sentinel 所需的最少配置如下所示:

    解读一下第一条指令的意思:

    其他选项的基本格式如下

学到这里我们进行实操一下,感受一下哨兵的威力!

    我们先在test目录下,新建三个配置文件:26379.conf、26380.conf、26381.conf(Sentinel服务器端口号默认是在redis服务器前拼个2),用 vi 命令创建这三个配置文件,然后我们在配置文件中写入一些简单的配置:

端口号:26379,哨兵名称:mymaster,主机地址:127.0.0.1,监控的redis端口号:6379,必须要2台从Sentinel服务器同意才会切换master,并进行故障迁移。(注意,这三个配置文件监控的redis服务器端口都是6379)

用相同的方法,创建了另外两个sentinel配置文件

我们先启动一个6379作为master

再启动6380、6381,作为两个slave

接下来正菜上场了!启动Sentinel!

可以发现,有两个slave正在跟随master,我们只要拿哨兵监控master,就可以看到有几个slave

我们继续启动,再接着启动两个Sentinel服务器

现在我们做一个小实验:如果我们将master服务器(6379)关闭,两个slave之间会发生什么?

当把master关闭之后,两个slave直接会有一段时间提示主服务器拒绝访问:

而哨兵开始也没有立马进行选举投票,选出新master,因为redis选举默认配的时间是有些长的,要过一点时间才开始选举投票,经过重新选举之后,sentinel选择了6381作为新的master。

那既然6381作为新秀,它应该有了很大的指导权,我们现在看看:

我们可以看到,在6381中设置的数据,确实在6380中可以查的到!说明6380在跟随6381,说明哨兵自动帮我们实现了故障转移。

我们再查看一下配置文件,看看有何变化?

可以发现,和原来我们写进去的2句配置完全不一样了,也就是说哨兵会自己改动配置文件。现在的master是6381。

接下来探讨一个问题:哨兵是如何发现其他哨兵的?

答案是:发布订阅机制。活着的master会去查看slave是谁,然后会去订阅其他的slave

我们可以用 psubscribe 去查看相关的发布订阅情况


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/140508.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-18
下一篇2023-03-18

发表评论

登录后才能评论

评论列表(0条)

    保存