Skip to content

主从与哨兵

主从复制(全量/增量)、哨兵的监控与故障转移、脑裂与数据丢失防御。

Updated View as Markdown
For humans

主从与哨兵

校招考察频度:☆ 中频(重点常考·大厂分水岭) 复习主线:高可用的第一层是主从复制(数据冗余与读写分离),第二层是哨兵 Sentinel(自动故障转移与拓扑变更通知)。面试高频主线:全量同步 vs 增量同步底层全流程、哨兵主观/客观下线与 Raft 选主机制、网络分区下的脑裂(Split-Brain)成因与参数级防御。


一、主从复制

主从复制拓扑

1. 同步过程(PSYNC 2.0 机制)

  1. 增量复制优先:从库连接主库发送 PSYNC <runid> <offset>,携带自身记录的主库 RunID 与复制偏移量。
  2. 判断是否能增量:
    • 若从库 RunID 与当前主库一致,且 offset 依然落在主库的环形复制积压缓冲区(repl_backlog_buffer)中,主库直接发送 CONTINUE,从缓冲区中把落后的命令增量补发给从库。
  3. 全量复制兜底:
    • 若首次连接(无 RunID)或网络中断时间过长导致从库 offset 已经被积压缓冲区覆盖(Backlog 溢出),主库触发全量同步:
    • 主库后台 bgsave 生成 RDB 快照并发送给从库,同时将期间新产生的所有写命令缓存到复制缓冲区(Replication Buffer)。
    • 从库清空本地旧数据、加载 RDB 文件,加载完毕后主库再将 Replication Buffer 增量命令刷给从库。
  • 核心注意点:
    • 复制是纯异步的:主库写入内存成功即向客户端返回 ACK,从库延迟毫秒到秒级不等。
    • 全量同步成本高昂:大实例生成和传输 RDB 严重占用磁盘 I/O 和网卡带宽,从库加载 RDB 期间会阻塞读请求。

二、哨兵(Sentinel):自动故障转移

哨兵集群解决“主库宕机后需要人工介入切主”的痛点。三大职责:

职责说明
监控(Monitoring)定期向所有主从节点及其他哨兵发送 PING 心跳,探测存活
自动故障转移(Failover)主库确认宕机后,自动从健康从库中选出一个升任新主,并重配其他从库挂载
配置中心与通知(Notification)发布订阅机制,实时通知客户端最新的主库 IP 和端口

1. 下线判定机制

  • 主观下线(sdown):单个哨兵在 down-after-milliseconds 内未收到主库有效 PING 回复,主观认为主库失联(防单点网络抖动误判)。
  • 客观下线(odown):该哨兵向其他哨兵发送 SENTINEL is-master-down-by-addr 询问。当确认主库失联的哨兵数量达到法定阈值(quorum,通常配置为 2/3 以上)时,主库被判定为客观下线。

2. 哨兵 Leader 选举与新主选择

  1. Raft 选出执行哨兵(Leader):达到客观下线后,各哨兵基于 Raft 协议互相投票,首个获得过半数(> N/2)选票的哨兵成为 Leader,全权负责执行故障转移。
  2. 从库选主四步过滤法:
    • ① 排除已下线、断连以及最近心跳超时的从库;
    • ② 优先选择 replica-priority 权重最高的从库;
    • ③ 权重相同时,选择**复制偏移量最大(数据最全、offset 最大)**的从库;
    • ④ 仍相同时,选择运行 ID(RunID)字典序最小的从库。

三、脑裂(Split-Brain)与数据丢失防御

脑裂是分布式主从系统在网络分区时最凶险的故障之一:

1. 脑裂是如何产生的?

[网络分区前]
Client  --->  Master (192.168.1.10)  --->  Replica-1, Replica-2
                       ^
                  Sentinel 集群

[网络分区后: 假死与双主并存]
【分区 A(少数派)】:
Client-1  --->  [旧 Master (假死/网络隔离)]  (客户端依然在向旧主写入数据!)

【分区 B(多数派)】:
Sentinel 集群 (达到 Quorum) ---> 判定旧主客观下线 ---> 选举 Replica-1 升为【新 Master】
Client-2  --->  [新 Master]
  1. 网络分区孤立:旧 Master 与大部分 Sentinel 及从节点失联,但与部分业务 Client 之间的网络仍通畅。
  2. 哨兵发起切换:多数派 Sentinel 发现旧 Master 心跳超时,将其判定为“客观下线”,投票从 Replica 中选举出新 Master。
  3. 双主并存:此时系统中同时存在两个“Master”。部分 Client 继续向旧 Master 写入,另一部分 Client 切换到新 Master 写入。
  4. 毁灭性数据丢失:当网络分区恢复后,Sentinel 会强制将旧 Master 降级为新 Master 的从库(Replica)。从库在首次与新主全量同步前,会执行 FLUSHDB 清空自身所有数据并加载新主的 RDB!旧 Master 在脑裂期间接收到的所有客户端写数据彻底永久丢失。

2. 工业界防御脑裂的两大参数

在 Redis 配置文件中开启以下协同参数:

# 主节点必须连接的最小良好从节点数(通常设为从节点总数的过半)
min-replicas-to-write 1

# 从节点向主节点发送 ACK(REPLCONF ACK)的最大允许延迟秒数(如 10 秒)
min-replicas-max-lag 10
  • 生效机制:
    • 主节点每个周期都会检查连接的从库状态与 ACK 延迟。
    • 一旦主节点发现健康从库数量 < min-replicas-to-write(例如网络隔离后健康从库为 0),或者从库心跳延迟 > 10s,主节点会立即自我拒绝所有写入请求,向客户端返回错误: -NOREPLICAS Not enough good replicas to write.
    • 这样最多只会丢失发生隔离后 10 秒以内的数据,杜绝旧主无限制接收脏写。
  • 代价权衡(CAP 权衡):
    • 开启该配置后,如果从库全部挂掉,主库将无法接收写操作(牺牲可用性 A,保住一致性 C)。
    • Redis 官方设计哲学始终偏向 AP(高可用与高性能),因此官方默认并未严格强制开启 min-replicas-to-write。面试时需要强调:“Redis 哨兵只能保证秒级恢复可用性(RTO),无法保证绝对零数据丢失(RPO=0)”。

面试追问

  1. 全量同步和增量同步? 首次或 backlog 溢出全量(RDB + 缓冲增量),正常增量(repl_backlog 补差)。
  2. 主从复制是同步的吗? 纯异步。主库写成功即返回,从库异步复制。强一致读需直读主库。
  3. 主观下线和客观下线的区别? 主观下线是单个哨兵的心跳超时判断;客观下线是达到 quorum 多数哨兵达成共识判定。
  4. 哨兵怎么选新主? 哨兵集群先 Raft 选出执行 Leader 哨兵,再按从库优先级、offset 复制进度、RunID 字典序四步淘汰选主。
  5. 脑裂怎么防? 配置 min-replicas-to-write 和 min-replicas-max-lag。当从节点失联或延迟超标时主库主动拒绝写,牺牲部分可用性来控制数据丢失窗口。
Navigation

Type to search…

↑↓ navigate↵ selectEsc close