MST

星途 面试题库

面试题:Redis Sentinel主观下线状态模型与集群故障转移的深度关联

阐述Redis Sentinel检测到主观下线状态后,如何进一步与客观下线判定以及最终的集群故障转移流程紧密配合,保证高可用性。请结合源码层面分析关键的触发条件、状态转换逻辑以及数据一致性的维护机制。
17.8万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

主观下线(Subjective Down,SDOWN)

  1. 触发条件:在Redis Sentinel源码中,当Sentinel对某个Redis实例进行定期PING检测时,如果在配置的 down-after-milliseconds 时间内,连续多次PING都没有得到响应,该Sentinel就会将这个实例标记为主观下线。相关源码在sentinel.csentinelIsInstanceAlive函数中:
// 判断实例是否存活
int sentinelIsInstanceAlive(sentinelRedisInstance *ri) {
    mstime_t delay = mstime() - ri->last_ping_time;
    // 超过配置的down-after-milliseconds时间无响应
    if (delay > ri->down_after_period) {
        // 标记为主观下线
        if (ri->flags & SRI_S_DOWN == 0) {
            sentinelEvent(LL_WARNING,"sdown",ri,"%@ %lld ms no-reply",
                sentinelRedisInstanceGetName(ri),
                (long long)delay);
            ri->flags |= SRI_S_DOWN;
        }
        return 0;
    }
    return 1;
}
  1. 状态转换逻辑:实例从正常状态转变为SDOWN状态,此时只有检测到的这个Sentinel认为该实例下线,其他Sentinel可能还认为该实例是正常的。

客观下线(Objective Down,ODOWN)

  1. 触发条件:当一个Sentinel将某个实例标记为主观下线后,它会向其他Sentinel发送 SENTINEL is-master-down-by-addr 命令,询问其他Sentinel对该实例的状态判断。如果同意该实例下线的Sentinel数量达到配置的 quorum 值(即多数Sentinel都认为该实例下线),就会将该实例标记为客观下线。在sentinel.csentinelSendIsMasterDownByAddr函数中:
// 发送SENTINEL is-master-down-by-addr命令
void sentinelSendIsMasterDownByAddr(sentinelRedisInstance *ri,
    sentinelRedisInstance *target, int myvote) {
    char buf[256];
    int len = snprintf(buf,sizeof(buf),
        "SENTINEL is-master-down-by-addr %s %d %d",
        sentinelRedisInstanceGetAddr(target),
        sentinelRedisInstanceGetPort(target),
        myvote);
    // 发送命令给其他Sentinel
    sentinelSend(ri,buf,len);
}
  1. 状态转换逻辑:从主观下线状态,在满足 quorum 条件后,转换为客观下线状态。此时,所有Sentinel都达成共识,认为该实例确实下线。

故障转移流程

  1. 触发条件:当一个主节点被标记为客观下线后,Sentinel集群开始进行故障转移。首先,Sentinel会从多个从节点中选举出一个新的主节点。选举的依据是从节点的优先级(配置的 slave-priority)、复制偏移量(replication offset)以及运行ID(runid)等。在sentinel.csentinelSelectSlave函数中:
// 选择一个从节点作为新的主节点
sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) {
    list *it, *slaves = listSearchKey(master->slaves, "slaves");
    sentinelRedisInstance *best = NULL;
    // 遍历从节点列表
    for (it = listFirst(slaves); it != NULL; it = listNext(it)) {
        sentinelRedisInstance *slave = listNodeValue(it);
        // 根据优先级、偏移量等条件选择最佳从节点
        if (best == NULL ||
            slave->slave_priority < best->slave_priority ||
            (slave->slave_priority == best->slave_priority &&
                slave->repl_offset > best->repl_offset))
        {
            best = slave;
        }
    }
    return best;
}
  1. 状态转换逻辑:新选举出的从节点会被提升为主节点,其他从节点会重新配置为新主节点的从节点。
  2. 数据一致性维护机制
    • 对于从节点,在故障转移过程中,新主节点选举出来后,从节点会与新主节点进行全量或部分复制,以保证数据的一致性。从节点通过发送 PSYNC 命令与主节点协商复制方式。
    • 在Sentinel层面,通过定期的心跳检测(PING命令)以及对节点状态的持续监控,确保所有节点状态的一致性。当有新节点加入或现有节点状态变化时,Sentinel会及时更新相关信息并通知其他Sentinel,从而保证整个集群对节点状态认知的一致性。