高可用机制全景:冗余、故障检测与故障转移
这篇解决什么问题:导师清单里的"HA 的机制"——高可用(High Availability)——是节点级故障(机器挂、进程挂、磁盘坏)下的生存能力,和下一篇容灾(机房级灾难)是两个层次。本篇给出高可用的完整机制体系:可用性指标(几个 9)→ 四大支柱(冗余 / 故障检测 / 故障转移 / 恢复)→ 故障检测的难点(心跳误判)→ 全组件 HA 机制对照表(MySQL/Redis/Kafka/etcd/K8s/Milvus)→ 无状态化与弹性 → 设计清单。
一、高可用是什么:先看指标
1.1 可用性 = 正常运行时间占比(几个 9)
| 可用性 | 每年停机 | 说明 |
|---|---|---|
| 99%(两个 9) | 87.6 小时 | 单机水平 |
| 99.9%(三个 9) | 8.76 小时 | 有主备、手动切换 |
| 99.99%(四个 9) | 52.6 分钟 | 自动故障转移 + 冗余 |
| 99.999%(五个 9) | 5.26 分钟 | 多活 + 容灾联动 |
1.2 决定可用性的两个数:MTBF 与 MTTR
可用性 = MTBF / (MTBF + MTTR)
- MTBF(平均无故障时间):多久挂一次——靠冗余和稳定性提升;
- MTTR(平均恢复时间):挂了多久能好——靠自动检测 + 自动转移缩短。
面试金句:"高可用就两件事:让故障少发生(MTBF),让故障快恢复(MTTR)。 99.99% 靠的不是'不挂',而是'挂了 52 分钟内自愈'。"
1.3 高可用 ≠ 强一致
高可用关心"服务在不在",一致性关心"数据对不对"(见 CAP 与 BASE)。提升可用性的手段(冗余、切换)往往会引入一致性问题(主从切换丢数据、双主脑裂)——所以每个 HA 方案都要回答"切换时丢多少数据"(RPO,见容灾)。
二、高可用的四大支柱
2.1 冗余:高可用的地基
无状态服务(API、网关、worker):多副本 + 负载均衡即可——任何副本挂了,负载均衡摘除它,流量给其他副本。这是最简单的高可用,所以架构上"尽量无状态"是第一原则。
有状态服务(数据库、缓存、队列):必须主备/主从 + 选主——主挂了,备顶上(选主机制详解)。冗余的代价是"多份数据要同步"(底层存储与数据同步)。
2.2 故障检测:HA 最难的部分
难点:无法确定"对方真挂了"还是"只是网络抖了一下"(网络通信与降级方案 一)。
| 检测手段 | 原理 | 误判代价 |
|---|---|---|
| 心跳(定时上报) | 超过 N 个周期没心跳 = 疑似挂 | 超时太短 → 误判切换(抖动就换主);太长 → 恢复慢 |
| 探活(主动请求) | 定期发健康检查请求(TCP/gRPC health) | 探活本身要设超时 |
| 租约(Lease) | 持有者持续续租,过期即失效 | 续租晚到 → 误判;见 选主机制详解 的 TTL 权衡 |
| gossip(谣言协议) | 节点互相传播"谁还活着" | 收敛慢,适合无主系统 |
防误判的工程做法(以 Redis 哨兵为例,必背):
① 主观下线(sdown):单个哨兵心跳超时 —— 只代表"这个哨兵认为挂了"
② 客观下线(odown):quorum 个哨兵都认为挂 —— 才真正触发切换模式提炼:"单点判断不可信,多数派仲裁才可信"——Redis 哨兵用 quorum,etcd 用多数派,K8s 用 kubelet 上报 + API Server 状态。任何 HA 系统都有"主观判断 → 客观仲裁"两级。
2.3 故障转移:冷备 / 温备 / 热备
| 类型 | 备机状态 | 切换时间(RTO) | 数据损失(RPO) |
|---|---|---|---|
| 冷备 | 没启动,只存备份 | 小时级(要启动 + 加载数据) | 大(最后一次备份之后的全丢) |
| 温备 | 已启动,数据在同步 | 分钟级 | 小(同步窗口内的丢) |
| 热备 | 实时同步 + 随时可切 | 秒级 | 最小(半同步/多数派确认下接近 0) |
切换的两种触发:自动(检测到故障即切)与手动(运维判断后切)。自动切换必须防脑裂——只有多数派/持有租约的一方才能成为新主(选主机制详解 四)。
2.4 恢复与自愈
- 进程级:进程崩溃 → supervisor/k8s 自动重启(
restartPolicy: Always); - 节点级:节点挂 → 负载均衡摘除 + 新节点自动补位(K8s ReplicaSet);
- 数据级:落后节点靠日志重放/快照追赶(etcd InstallSnapshot、MySQL binlog 追平、Kafka follower 拉取);
- 弹性:流量涨 → HPA 自动扩容(见 S7 K8s 调度与控制器)。
三、全组件 HA 机制对照表(面试背这张表)
| 组件 | 冗余方式 | 故障检测 | 故障转移 | 丢数据边界 | 对应章节 |
|---|---|---|---|---|---|
| MySQL | 主从 / 半同步 / MGR | 半同步 ACK / 组复制多数派 | MHA 选从提升 / MGR 自动选主 | 异步丢延迟窗口;半同步正常不丢,超时降级丢 | S1 主从复制与高可用 |
| Redis | 主从 + 哨兵 / Cluster | 哨兵主观 + 客观下线 | 哨兵 failover / Cluster 从提升 | 异步复制丢未同步写;脑裂靠 min-replicas 防 | S2 持久化与高可用 |
| Kafka | 分区副本(ISR) | ISR 同步状态 | ISR 中选新 leader;controller 重选 | acks=all+min.insync.replicas≥2 不丢;降级后丢 | S3 可靠性与积压 |
| etcd | Raft 多数派 | 选举超时 + 心跳 | 多数派选新 Leader | 已提交不丢;少数派拒绝服务 | Raft 算法详解 |
| K8s 控制面 | API Server 多副本 + etcd 集群 | 探针(liveness/readiness) | etcd 多数派 + controller leader-elect | 见 S7 高可用与故障排查 | |
| Milvus | 组件多副本 + coordinator 选主 | 组件心跳 | etcd 选主切换 | 存算分离下 WAL 保证不丢 | S10 部署监控 |
| Nginx/LB | 主备 + VIP(keepalived) | 心跳 + 探活 | VIP 漂移 | 无数据 | — |
规律(面试讲这个规律比背表加分):所有 HA 组件都遵循同一个模式——冗余(多副本)→ 检测(心跳/多数派仲裁)→ 转移(选主/提升)→ 追平(日志重放)。差别只在"同步多严"(决定丢多少)和"仲裁多严"(决定多快切换)。
四、无状态化与弹性:高可用的架构级手段
4.1 无状态化是最高性价比的 HA
有状态(session、本地缓存、本地文件)→ 实例挂了状态就没了 → 依赖故障转移。无状态 → 任何实例都能接任何请求 → 多副本 + LB 就是完整 HA。
迁移手段(面试讲 1~2 个):
| 手段 | 做法 |
|---|---|
| 会话外置 | session 从本地内存搬到 Redis/etcd |
| 本地缓存下沉 | 本地缓存换成 Redis 分布式缓存(或降级容忍冷缓存) |
| 状态外置 | 处理中的任务状态放 DB/MQ,worker 无状态化(重跑可恢复) |
4.2 优雅上下线(HA 的收尾动作)
上线/下线的瞬间最容易出错:上线没预热就接流量 → 被打垮;下线直接杀 → 丢在途请求。标准流程(S4 治理与稳定性):信号 → 停止接新请求 → 处理在途 → 注销 → 退出;Go 里 signal.NotifyContext + server.Shutdown(ctx)。
4.3 故障域设计
故障域:一次故障影响的物理范围。机器 → 机架 → 机房 → 城市。HA 设计原则:副本放在不同的故障域(至少不同机器,重要数据跨机架/跨机房),否则"同一机架断电 = 所有副本一起挂"——这是容灾的入口。
五、高可用设计清单(写系统时逐条过)
- [ ] 无状态服务:多副本 + 负载均衡 + 健康检查?
- [ ] 有状态服务:主备/主从 + 自动选主(etcd/哨兵)?
- [ ] 故障检测:心跳/探活有超时?有"主观 → 客观"两级仲裁防误判?
- [ ] 故障转移:自动还是手动?RTO 目标多少?防脑裂(多数派/租约/fencing)?
- [ ] 数据安全:切换时 RPO 多少?同步级别够不够?(半同步/多数派)
- [ ] 恢复:进程崩溃自动重启?落后节点日志追赶?数据备份(容灾)?
- [ ] 弹性:流量翻倍能自动扩容?优雅上下线流程正确?
- [ ] 可观测:故障时能快速定位(指标/告警/链路)?(S4 可观测性)
面试追问
- 问:99.99% 是怎么算出来的? 可用性 = MTBF/(MTBF+MTTR);99.99% = 每年停机 ≤ 52.6 分钟,靠自动检测 + 自动转移缩短 MTTR。
- 问:心跳多久算超时? 权衡误判与恢复速度:心跳间隔 × N 倍(如 3~5 个周期);关键系统加"主观 + 客观"两级仲裁(哨兵 quorum、etcd 多数派)。
- 问:主从切换会丢数据吗? 取决于同步方式:异步丢"延迟窗口内未同步写";半同步正常不丢(超时降级丢);多数派确认不丢已提交写(RPO 逐级递减,对应容灾的同步级别)。
- 问:为什么尽量无状态? 无状态 = 多副本 + LB 即 HA,不需要选主/切换/数据追平这些复杂机制;有状态才有主备、脑裂、丢数据问题。
- 问:所有 HA 机制的共同模式? 冗余 → 检测(多数派仲裁)→ 转移(选主/提升)→ 追平(日志重放);MySQL/Redis/Kafka/etcd 全部是这个模式,差别在同步严格度和仲裁方式。