推荐渐进式解析 Redis 源码 - 哨兵 sentinel 上面有讲解的主观下线和客观下线
前言
下面是我摘抄的有关主观下线和客观下线的介绍:
-
主观下线 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进行有效响应的时候,那 主观下线状态就会被移除 - 接上面,如果还是 客观下线状态,就需要进行 主服务器 选举逻辑
sentinelCheckSubjectivelyDown(主观下线)
在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) {
quorum = 1;
di = dictGetIterator(master->sentinels);
while((de = dictNext(di)) != NULL) {
sentinelRedisInstance *ri = dictGetVal(de);
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;
}
}
}
|