Sentinel(哨兵)

Sentinel(哨兵)

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

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

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

1 启动并初始化Sentinel

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

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

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

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

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

    为什么有两个连接?

    在Redis目前的发布与订阅功能中,被发送的信息都不会保存在Redis服务器里面,如果在信息发送时,想要接收信息的客户端不在线或者断线,那么这个客户端就会丢失 这条信息。 因此,为了不丢失_sentinel_:hello频道的任何信息, Sentinel必须 专门用一个订阅连接来接收该频道的信息。另一方面, 除了订阅频道之外, Sentinel还必须向主服务器发送命令, 以此来与主 服务器进行通信, 所以Sentinel还必须向主服务器创建命令连接。   

    因为Sentinel需要与多个实例创建多个网络连接, 所以Sentinel使用的是异步连接。

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

2 获取主服务器信息

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

Sentinel向带有三个从服务器的主服务器发送INFO命令

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

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

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

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

主服务器和它的三个从服务器


3 获取从服务器信息

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

Sentinel与各从服务器建立命令连接和订阅连接

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

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

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

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

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

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

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

Sentinel同时向服务器发送和接收信息.

    对于监视同一个服务器的多个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会为源Sentinel创建一个新的实例结构,并将这个结构添加到sentinels属性里面。

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

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

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

各个Sentinel之间的网络连接

                                            Sentinel之间不会创建订阅连接

    Sentinel在连接主服务器或者从服务器时,会同时创建命令连接和订阅连接,但是 在连接其他Sentinel时,却只会创建命令连接,而不创建订阅连接。 这是因为Sentinel 需要通过接收主服务器或者从服务器发来的频道信息来发现未知的新Sentinel, 所以才需要建立订阅连接,而相互已知的Sentinel只要使用命令连接来进行通信就足够了。 

6 检测主观下线状态

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

主服务器被标识为主观下线

7 检查客观下线状态

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


主服务器被标记为客观下线

8 选举领头Sentinel

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

    选举领头Sentinel规则和方法:

**所有在线的Sentinel都有被选为领头Sentinel的资格。

**每个发现主服务器进入客观下线的Sentinel都会要求其他Sentinel将自己设置为局部领头Sentinel。

**Sentinel设置局部领头Sentinel的规则是先到先得:最先向目标Sentinel发送设置要求的源Sentinel将成为目标Sentinel的局部领头Sentinel,而之后接收到的所有设置要求都会被拒绝。

**如果某个Sentinel被半数以上的Sentinel设置为局部领头Sentinel,那么这个Sentinel成为Sentinel。

**如果在给定的时限内,没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将在一段时间之后再进行选举,直到选出领头Sentinel为止。

注:上述只是选举领头Sentinel的大致思路。

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

三个Sentinel都发现了主服务器进入客观下线状态


Sentinel再次向其他Sentinel发送命令

9 故障转移

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

1) 在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器,并将其转换为 主服务器。

2) 让巳下线主服务器属下的所有从服务器改为复制新的主服务器。

3) 将已下线主服务器设置为新的主服务器的从服务器, 当这个旧的主服务器重新上线时,它就会成为新的主服务器的从服务器

    (1) 选出新的主服务器

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

                                       新的主服务器是怎么挑选出来的

领头Sentinel会将已下线的主服务器的所有从服务器存到一个列表里,然后按照以下规则一条条过滤:

    1) 过滤掉列表中所有下线或断线状态的从服务器。

    2) 过滤掉列表中所有最近5秒内没有回复过领头Sentinel的INFO命令的从服务器。

    3) 过滤掉所有与已下线的主服务连接断开超过规定时长的从服务器,这是为了保证列表中剩余服务器没有过早的与主服务器断开连接,保证列表中从服务器数据都是比较新的。

    4) 之后,按照从服务器的优先级,对列表中剩余的从服务器排序,选出优先级最高的从服务器;如果存在相同的,则比较从服务器的复制偏移量,选出其中较大的;如果还是存在相同的,则选出运行ID最小的作为主服务器。

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

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

将server3升级为主服务器


server3成功升级为主服务器

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

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

让从服务器复制新的主服务器
server2和server4成为server3的从服务器

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

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

server1被设置为新的主服务器的从服务器

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

server1重新连上并成为server3的从服务器

10 小结

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

  (1) 定时任务

    **每隔10秒,每个Sentinel会向服务器的_sentinel_:hello频道发送INFO命令,并根据命令的回复信息创建或更新相应的实例结构。

    **每隔2秒,每个Sentinel通过命令连接向所有被监视的主从服务器发送自己当前的信息以及对主服务器的认知信息。同时每个Sentinel也会订阅该频道,来了解其他Sentinel节点以及它们对主服务器的认知。

    **每隔1秒,每隔Sentinel会向主服务器、从服务器、其余Sentinel发送一条PING命令,并根据回复信息来确认它们是否在线,如果在规定的时间内(通过参数down-after-milliseconds控制)没有进行有效的回复(除了PONG、-LOADING、-MASTERDOWN之外的回复,或者不回复),Sentinel会判定该实例已经进入主观下线。

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

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

  (3) 领头Sentinel的选举

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

  (4) 故障转移

  **在已下线的主服务器属下的所有从服务器中根据一定的规则选出一个从服务器,并将其转换为主服务器。

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

 **将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器上线后,它就会成为新的主服务器的从服务器。

本文完


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


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 1.概述 Sentinel(哨岗、哨兵)是Redis高可用性的解决方案:由一个或多个Sentinel实例组成的Se...
    孤尘F阅读 777评论 0 0
  • Sentinel是Redis高可用的体现:通过多个Sentinel实例组成的Sentinel系统可以监视多个主服务...
    剑客kb阅读 361评论 0 0
  •   当主机宕机后出现故障无法及时恢复,可以在从机执行slave no one命令使其上位变为主机,其他主机会自动跟...
    纸中圆阅读 840评论 0 3
  • Sentinel是Redis的高可用性解决方案,本文主要介绍Sentinel的初始化过程及其与一般Redis服务器...
    wenmingxing阅读 3,036评论 1 5
  • 1,sentinel简介 1)能监控master、slave、监控同一master其他的sentinel。2)存有...
    沐兮_d64c阅读 688评论 0 2