Redis 6.2 sentinel判断主观下线和客观下线(源码)

推荐渐进式解析 Redis 源码 - 哨兵 sentinel 上面有讲解的主观下线和客观下线

前言

下面是我摘抄的有关主观下线和客观下线的介绍:

  • 主观下线 SDOWN: 如果 监控的服务器节点 在 down-after-milliseconds
    设置的毫秒时效内没有响应检测,则会被判定为 主观下线;这个状态适用所有服务器节点

  • 客观下线 ODOWN: 主服务器节点在发生故障的时候,sentinel 会通过 is-master-down-by-addr 命令向其他 sentinel 节点询问 该主服务器节点的状态,如果超过 quorum 个数的哨兵节点都认为 主服务器节点不可达,则判定为客观下线;这个状态只会针对 主服务器节点(对于从服务器没有客观下线,从下面源码中能找到答案)

那客观下线与主观下线与sentinel 关系其实也是redissentinel的交互

  1. 每个 sentinel 以 每秒一次 的频率,向它所知的 主服务器节点 和 从服务器节点 以及其他 sentinel节点 发送PING 命令,检测其状态
  2. 如果一个 节点 或者 实例 距离 最后一次 有效回复 PING 命令的时间超过 down-after-milliseconds设定的值,那么这个 节点 或者 实例会被 sentinel 标记为 SDOWN 主观下线
  3. 随后正在监控这个 主服务器节点 的所有 sentinel 都要以每秒一次的频率确认这个 主服务器节点 是否真正进入了 主观下线状态,一旦有 足够数量 的 sentinel 在指定时间范围内同意这个下线判断,那么这个 服务器就要被标记为 ODOWN 客观下线,然后sentinel 向 客观下线主服务器 的所有 从服务器 发送 INFO 命令的频率,会从 10 秒一次改为 每秒一次
  4. 当然,如果 中途当没有足够数量的 sentinel 同意下线判断,那这个 客观下线 状态就会被移除,而且当 主服务器重新对 PING进行有效响应的时候,那 主观下线状态就会被移除
  5. 接上面,如果还是 客观下线状态,就需要进行 主服务器 选举逻辑

sentinelCheckSubjectivelyDown(主观下线)

sentinelHandleRedisInstance方法下有sentinelCheckSubjectivelyDown方法来进行判定,
主要的流程:如果 监控的服务器节点 在 down-after-milliseconds 设置的毫秒时效内没有响应检测,则会被判定为 主观下线;这个状态适用所有服务器节点


/* Is this instance down from our point of view?
从主观的角度看这个实例是否是下线状态*/
void sentinelCheckSubjectivelyDown(sentinelRedisInstance *ri) {
    mstime_t elapsed = 0;
    // 获取命令响应已经过去的时长
    if (ri->link->act_ping_time)
        elapsed = mstime() - ri->link->act_ping_time;
    // 实例连接断开了
    else if (ri->link->disconnected)
        elapsed = mstime() - ri->link->last_avail_time;

    /* Check if we are in need for a reconnection of one of the
     * links, because we are detecting low activity.
     *低活跃度重新连接,即 连接超过了 1.5秒,并且之前发送了 PING 命令但是活跃度很低
     * 1) Check if the command link seems connected, was connected not less
     *    than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have a
     *    pending ping for more than half the timeout.
     检查命令链接是否似乎已连接,连接时间不少于 SENTINEL_MIN_LINK_RECONNECT_PERIOD,但我们仍有超过一半超时的待处理 ping*/
    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... */
        /* The pending ping is delayed, and we did not receive
         * error replies as well. */
        (mstime() - ri->link->act_ping_time) > (ri->down_after_period/2) &&
        (mstime() - ri->link->last_pong_time) > (ri->down_after_period/2))
    {
         // 断开实例的连接
        instanceLinkCloseConnection(ri->link,ri->link->cc);
    }

    /* 2) Check if the pubsub link seems connected, was connected not less
     *    than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have no
     *    activity in the Pub/Sub channel for more than
     *    SENTINEL_PUBLISH_PERIOD * 3.
     */
      // 检查 订阅发布的连接是不是也是出于 低活跃度
    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))
    {    // 断开实例连接
        instanceLinkCloseConnection(ri->link,ri->link->pc);
    }

    /* Update the SDOWN flag. We believe the instance is SDOWN if:
     *更新 SDOWN 标志。我们认为实例是 SDOWN 如果
     * 1) It is not replying. 它没有回复
     * 2) We believe it is a master, it reports to be a slave for enough time
     *    to meet the down_after_period, plus enough time to get two times
     *    INFO report from the instance. sentinel 认为是主节点但是 报告是从节点*/
    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)))
    {
        /* Is subjectively down // 设置主观下线标识*/
        if ((ri->flags & SRI_S_DOWN) == 0) {
            sentinelEvent(LL_WARNING,"+sdown",ri,"%@");
            ri->s_down_since_time = mstime();
            ri->flags |= SRI_S_DOWN;
        }
    } else {
        /* Is subjectively up  // 如果已经是主观下线状态,则取消标识*/
        if (ri->flags & SRI_S_DOWN) {
            sentinelEvent(LL_WARNING,"-sdown",ri,"%@");
            ri->flags &= ~(SRI_S_DOWN|SRI_SCRIPT_KILL_SENT);
        }
    }
}

sentinelCheckObjectivelyDown(客观下线)

sentinelHandleRedisInstance方法下的sentinelCheckObjectivelyDown方法,这里需要注意的是,客观下线是针对主服务器节点才能做的状态标识,从服务器节点就不会有这个状态标识

/* Is this instance down according to the configured quorum?
 *
 * Note that ODOWN is a weak quorum, it only means that enough Sentinels
 * reported in a given time range that the instance was not reachable.
 * However messages can be delayed so there are no strong guarantees about
 * N instances agreeing at the same time about the down state.
 请注意,ODOWN 是一个弱仲裁,它仅表示在给定时间范围内报告了足够多的 Sentinel 报告该实例无法访问。但是消息可能会延迟,因此无法保证 N 个实例同时同意关闭状态*/
void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) {
    dictIterator *di;
    dictEntry *de;
    unsigned int quorum = 0, odown = 0;
     // 如果已经被判断为主观下线
    if (master->flags & SRI_S_DOWN) {
        /* Is down for enough sentinels? */
        // 当前 哨兵认为下线,投票1
        quorum = 1; /* the current sentinel. */
        /* Count all the other sentinels. */
        di = dictGetIterator(master->sentinels);
        // 遍历所有监控该主节点的所有 sentinel
        while((de = dictNext(di)) != NULL) {
            sentinelRedisInstance *ri = dictGetVal(de);
             // 如果 sentinel 投票主观下线,投票 +1
            if (ri->flags & SRI_MASTER_DOWN) quorum++;
        }
        dictReleaseIterator(di);
         // 如果投票数够了,则认为 客观下线
        if (quorum >= master->quorum) odown = 1;
    }

    /* Set the flag accordingly to the outcome. */
     // 如果已经判定为 客观下线了
    if (odown) {
     // 如果主服务器节点还没改变状态,则修改其 客观下线状态
        if ((master->flags & SRI_O_DOWN) == 0) {
            sentinelEvent(LL_WARNING,"+odown",master,"%@ #quorum %d/%d",
                quorum, master->quorum);
            master->flags |= SRI_O_DOWN;
            master->o_down_since_time = mstime();
        }
    } else {
     // 如果票数不足,原本 客观下线就要改回来为 主观下线
        if (master->flags & SRI_O_DOWN) {
            sentinelEvent(LL_WARNING,"-odown",master,"%@");
            master->flags &= ~SRI_O_DOWN;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值