文章目录推荐渐进式解析 Redis 源码 - 哨兵 sentinel 上面有讲解的主观下线和客观下线
前言sentinelCheckSubjectivelyDown(主观下线)sentinelCheckObjectivelyDown(客观下线)
前言下面是我摘抄的有关主观下线和客观下线的介绍:
主观下线 SDOWN: 如果 监控的服务器节点 在 down-after-milliseconds
设置的毫秒时效内没有响应检测,则会被判定为 主观下线;这个状态适用所有服务器节点
客观下线 ODOWN: 主服务器节点在发生故障的时候,sentinel 会通过 is-master-down-by-addr 命令向其他 sentinel 节点询问 该主服务器节点的状态,如果超过 quorum 个数的哨兵节点都认为 主服务器节点不可达,则判定为客观下线;这个状态只会针对 主服务器节点(对于从服务器没有客观下线,从下面源码中能找到答案)
那客观下线与主观下线与sentinel 关系其实也是redis和sentinel的交互
- 每个 sentinel 以 每秒一次 的频率,向它所知的 主服务器节点 和 从服务器节点 以及其他 sentinel节点 发送PING 命令,检测其状态如果一个 节点 或者 实例 距离 最后一次 有效回复 PING 命令的时间超过 down-after-milliseconds设定的值,那么这个 节点 或者 实例会被 sentinel 标记为 SDOWN 主观下线随后正在监控这个 主服务器节点 的所有 sentinel 都要以每秒一次的频率确认这个 主服务器节点 是否真正进入了 主观下线状态,一旦有 足够数量 的 sentinel 在指定时间范围内同意这个下线判断,那么这个 服务器就要被标记为 ODOWN 客观下线,然后sentinel 向 客观下线主服务器 的所有 从服务器 发送 INFO 命令的频率,会从 10 秒一次改为 每秒一次当然,如果 中途当没有足够数量的 sentinel 同意下线判断,那这个 客观下线 状态就会被移除,而且当 主服务器重新对 PING进行有效响应的时候,那 主观下线状态就会被移除接上面,如果还是 客观下线状态,就需要进行 主服务器 选举逻辑
在sentinelHandleRedisInstance方法下有sentinelCheckSubjectivelyDown方法来进行判定,
主要的流程:如果 监控的服务器节点 在 down-after-milliseconds 设置的毫秒时效内没有响应检测,则会被判定为 主观下线;这个状态适用所有服务器节点
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;
if (ri->link->cc &&
(mstime() - ri->link->cc_conn_time) >
SENTINEL_MIN_link_RECONNECT_PERIOD &&
ri->link->act_ping_time != 0 &&
(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);
}
// 检查 订阅发布的连接是不是也是出于 低活跃度
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);
}
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(客观下线)
sentinelHandleRedisInstance方法下的sentinelCheckObjectivelyDown方法,这里需要注意的是,客观下线是针对主服务器节点才能做的状态标识,从服务器节点就不会有这个状态标识
void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) {
dictIterator *di;
dictEntry *de;
unsigned int quorum = 0, odown = 0;
// 如果已经被判断为主观下线
if (master->flags & SRI_S_DOWN) {
// 当前 哨兵认为下线,投票1
quorum = 1;
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;
}
// 如果已经判定为 客观下线了
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;
}
}
}



