Skip to content

高可用机制全景:冗余、故障检测与故障转移 ​

属于 S8 分布式理论 · 能力强化 · 第七篇(导师清单:HA 的机制) 上一篇:限流与熔断 下一篇:容灾与备份恢复

这篇解决什么问题:导师清单里的"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 哨兵为例,必背):

text
① 主观下线(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 可靠性与积压
etcdRaft 多数派选举超时 + 心跳多数派选新 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 全部是这个模式,差别在同步严格度和仲裁方式。

持续学习,持续构建。