8288分类目录 8288分类目录 8288分类目录
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

(十六)高并发redis学习笔记:哨兵底层原理以及slave选举算法

来源:本站原创 浏览:123次 时间:2021-10-16

文章目录

  • 1、sdown和odown转换机制
  • 2、哨兵集群的自动发现机制
  • 3、slave配置的自动纠正
  • 4、slave->master选举算法
  • 5、quorum和majority
  • 6、configuration epoch
  • 7、configuraiton传播


1、sdown和odown转换机制

sdown和odown两种失败状态:

  • sdown是主观宕机,就一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机。sdown达成的条件很简单,如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就主观认为master宕机
  • odown是客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机。

sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum指定数量的其他哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机。

我们可以通过源码来看看哨兵是如何工作的:
首先,在定时任务severCron()函数中,如果发现是哨兵则会执行哨兵的计时器sentinelTimer()。

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {    ...    /* Run the Sentinel timer if we are in sentinel mode. */    if (server.sentinel_mode) sentinelTimer();    ...}

在sentinelTimer()计时器中,会针对每一个哨兵进行处理,调用函数为sentinelHandleDictOfRedisInstances(),检查所有的实例。

void sentinelTimer(void) {    ...    sentinelHandleDictOfRedisInstances(sentinel.masters);    ...}

在sentinelHandleDictOfRedisInstances()函数中,主要是递归遍历,调用sentinelHandleRedisInstance()对实例进行处理。

void sentinelHandleRedisInstance(sentinelRedisInstance *ri) {    sentinelReconnectInstance(ri);    // 发送ping消息给这个实例    sentinelSendPeriodicCommands(ri);    if (sentinel.tilt) {        if (mstime()-sentinel.tilt_start_time < SENTINEL_TILT_PERIOD) return;        sentinel.tilt = 0;        sentinelEvent(LL_WARNING,"-tilt",NULL,"#tilt mode exited");    }    // 判断是否主观下线    sentinelCheckSubjectivelyDown(ri);        if (ri->flags & (SRI_MASTER|SRI_SLAVE)) {        /* Nothing so far. */    }    // 只针对master节点    if (ri->flags & SRI_MASTER) {        // 判断是都客观下线        sentinelCheckObjectivelyDown(ri);        if (sentinelStartFailoverIfNeeded(ri))            sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_ASK_FORCED);        sentinelFailoverStateMachine(ri);        sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_NO_FLAGS);    }}

如何判断主观下线:

void sentinelCheckSubjectivelyDown(sentinelRedisInstance *ri) {    mstime_t elapsed = 0;    // act_ping_time:最后一个未完成的ping(之后没有收到pong)发出的时间。当接收到一个pong时,该字段被设置为0,如果该值为0并且发送了一个新的ping,则再次设置为当前时间。(说明已经出现ping过没回复)    if (ri->link->act_ping_time)        elapsed = mstime() - ri->link->act_ping_time;    else if (ri->link->disconnected)        // 连接不上,还没有出现ping过没回复        elapsed = mstime() - ri->link->last_avail_time;    // 如果检测到连接的活跃度(activity)很低,那么考虑重断开连接,并进行重连    if (ri->link->cc &&        (mstime() - ri->link->cc_conn_time) >        SENTINEL_MIN_LINK_RECONNECT_PERIOD &&        ri->link->act_ping_time != 0 && /* There is a pending ping... */        (mstime() - ri->link->act_ping_time) > (ri->down_after_period/2) &&        (mstime() - ri->link->last_pong_time) > (ri->down_after_period/2))    {        // 连接时长已超过最短连接间隔 ping已经发出,但在down_after_period/2的时间内没有收到pong响应        // 断开实例的cc连接(命令连接)        instanceLinkCloseConnection(ri->link,ri->link->cc);    }   // 最后一次从这个服务器接收消息的时间大于发布publish的最大时间的3倍,也就是6秒时断开订阅频道信息的连接    if (ri->link->pc &&        (mstime() - ri->link->pc_conn_time) >         SENTINEL_MIN_LINK_RECONNECT_PERIOD &&        (mstime() - ri->link->pc_last_activity) > (SENTINEL_PUBLISH_PERIOD*3))    {        // 断开发布订阅的连接 pc        instanceLinkCloseConnection(ri->link,ri->link->pc);    }        //现在距离上次ping的时间已经超过了down_after_period,可以判定为主观宕机    if (elapsed > ri->down_after_period ||        (ri->flags & SRI_MASTER &&         ri->role_reported == SRI_SLAVE &&         mstime() - ri->role_reported_time >          (ri->down_after_period+SENTINEL_INFO_PERIOD*2)))    {        //判断为主观宕机        if ((ri->flags & SRI_S_DOWN) == 0) {            // 发送事件            sentinelEvent(LL_WARNING,"+sdown",ri,"%@");            // 记录主观宕机的时间            ri->s_down_since_time = mstime();            //更新主观宕机的状态            ri->flags |= SRI_S_DOWN;        }    } else {        /* 它活过来了,判定会不宕机*/        if (ri->flags & SRI_S_DOWN) {            // 发送事件            sentinelEvent(LL_WARNING,"-sdown",ri,"%@");            // 移除掉之前的宕机标识            ri->flags &= ~(SRI_S_DOWN|SRI_SCRIPT_KILL_SENT);        }    }}

如何判断客观宕机,sentinelCheckObjectivelyDown(ri):

void sentinelCheckObjectivelyDown(sen����,����tinelRedisInstance *master) {    dictIterator *di;    dictEntry *de;    unsigned int quorum = 0, odown = 0;    //当前的sentinel判断它为客观单价    if (master->flags & SRI_S_DOWN) {        /* Is down for enough sentinels? */        //需要满足条件        quorum = 1; /* the current sentinel. */        /* Count all the other sentinels. */        // 遍历所有的sentinel        di = dictGetIterator(master->sentinels);        while((de = dictNext(di)) != NULL) {            sentinelRedisInstance *ri = dictGetVal(de);            if (ri->flags & SRI_MASTER_DOWN) quorum++;        }        //释放迭代器        dictReleaseIterator(di);        //是否满足认同数量大于等于quorum,满足则认为是客观宕机(odown)        if (quorum >= master->quorum) odown = 1;    }    /* 如果是odown*/    if (odown) {        if ((master->flags & SRI_O_DOWN) == 0) {            // 发送事件             sentinelEvent(LL_WARNING,"+odown",master,"%@ #quorum %d/%d",                quorum, master->quorum);                // 设置odown标识            master->flags |= SRI_O_DOWN;            // 记录事件            master->o_down_since_time = mstime();        }    } else {        if (master->flags & SRI_O_DOWN) {            // 没有进入odown,发送事件            sentinelEvent(LL_WARNING,"-odown",master,"%@");            // 移除标识            master->flags &= ~SRI_O_DOWN;        }    }}

2、哨兵集群的自动发现机制

哨兵互相之间的发现,是通过redis的pub/sub系统实现的,每个哨兵都会往__sentinel__:hello这个channel里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在。
消息主要包括:

  • s_ip: sentinel的ip
  • s_port: sentinel的端口port
  • s_runnid:sentinel的runnid
  • s_epoch:纪元,版本
  • m_name:master的名称
  • m_ip:master的ip
  • m_port:master 的端口
  • m_epoch:master的epoch

每隔两秒钟,每个哨兵都会往自己监控的某个master+slaves对应的__sentinel__:hellochannel里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置

每个哨兵也会去监听自己监控的每个master+slaves对应的__sentinel__:hello channel,然后去感知到同样在监听这个master+slaves的其他哨兵的存在

每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步

3、slave配置的自动纠正

哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据; 如果slave连接到了一个错误的master上,比如故障转移之后,那么哨兵会确保它们连接到正确的master上

4、slave->master选举算法

如果一个master被认为odown了,而且majority哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来,优先级会考虑slave的一些信息。

  • (1)跟master断开连接的时长,如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,也就是:(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state ,那么slave就被认为不适合选举为master,被排除掉。(这个仅仅是用于排除,不用于排序),剩下的执行后面的三个比较。
  • (2)slave优先级,slave priority越低,优先级就越高,这个是可以进行配置的。默认是100,越小越优先。
  • (3)复制offset,如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高
  • (4)run id,选择一个run id比较小的那个slave
5、quorum和majority

每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个哨兵来做切换,这个哨兵还得得到majority哨兵的授权,才能正式执行切换

如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换

但是如果quorum >= majority,那么必须quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换。

这个quorum是我们自己设置的, majority是客观存在的。

6、configuration epoch

哨兵会对一套redis master+slave进行监控,有相应的监控的配置,也就是可以理解为配置版本。

执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的

如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号。

7、configuraiton传播

哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub消息机制。要知道,主备切换是一个哨兵在干,干完了总得让别人知道是不是。

这里之前的version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的。其他的哨兵会订阅这个消息,发现更新的epoch就认为master已经切换过了,接着把自己存的信息更新。这样,就可以保持哨兵里面的信息一致性了。

此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~

技术之路不在一时,山高水长,纵使缓慢,驰而不息。


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net