高可用(High Availability)在维基百科中的定义是:
系统无中断地执行其功能的能力
但这个定义容易让人产生误解——以为高可用是要让系统"永远不宕机"。实际上,任何硬件都会故障,任何软件都会有 bug,物理定律决定了故障不可避免。
真正的高可用不是"不故障",而是"快速恢复"。99.99% 的可用性意味着每年约 52 分钟的停机时间,这个目标才现实可及。
高可用之所以成为架构复杂度的来源,是因为它的本质手段——冗余——会引发连锁反应:
故障不可避免 ↓ 冗余(增加副本) ↓ 副本间的状态同步 ↓ 状态一致性挑战 ↓ 决策机制的复杂性 ↓ 引入更多边界情况
每一步都可能出错,每一次防护都可能引入新的问题。
计算的本质是纯函数——相同的输入在哪里执行,输出都一样。这使得计算可以自由迁移:
请求 A → 任意副本 → 结果相同
计算冗余的实现相对简单,因为副本之间不需要共享状态。
存储的本质是有状态——数据必须保持一致。存储副本之间必须同步,而同步需要时间:
写入节点 A(耗时 X ms) ↓ 同步到节点 B(耗时 Y ms) ↓ 节点 B 的数据才可用
毫秒级的延迟对人类来说无感,但对系统状态一致性来说是本质性的挑战。
单机升级为双机,首要增加的是任务分配器(Load Balancer)。
但分配器本身也需要高可用,于是引入一个问题:分配器的高可用又如何保证?
几种常见的分配策略:
| 策略 | 描述 | 适用场景 |
|---|---|---|
| DNS 轮询 | 简单,但生效慢 | 勉强可用 |
| L4 负载均衡 | 性能好,但贵 | 高并发 |
| L7 负载均衡 | 功能强,灵活 | 复杂路由 |
双机部署有两种基本模式:
主备(Active-Standby)
主主(Active-Active)
备机的备份程度又分三种:
| 类型 | 备机状态 | 切换速度 | 资源消耗 |
|---|---|---|---|
| 冷备 | 完全关闭 | 慢(需要启动) | 最低 |
| 温备 | 接收请求但不处理 | 中 | 中 |
| 热备 | 同步接收所有请求 | 快 | 最高 |
数据同步需要经过网络,而网络的延迟是物理限制:
| 场景 | 延迟量级 |
|---|---|
| 同机房 | 1-5 ms |
| 同城多机房 | 10-30 ms |
| 跨区域(北上广) | 30-50 ms |
| 跨国 | 100-500 ms |
这意味着在某个时间窗口内,系统数据必然不一致。这个时间窗口无法消除,只能缩小。
物理线路会中断,而且恢复时间长:
| 事件 | 影响时间 |
|---|---|
| 挖断光缆 | 几小时 |
| 海底光缆故障 | 几小时 |
| BGP 故障 | 几十分钟 |
2015 年支付宝某次故障就是因为光缆被挖断,业务中断超过 4 小时。
CAP 定理说:分布式系统无法同时满足一致性(Consistency)、可用性(Availability)、分区容错(Partition tolerance)。
对存储高可用的实际指导意义:
| 业务场景 | 优先级 | 说明 |
|---|---|---|
| 金融、账务 | C > A | 宁可不可用,也要数据一致 |
| 社交Feed | A > C | 用户体验优先,允许短暂不一致 |
| 日志、监控 | P 优先 | 允许丢失,但不能不可用 |
没有"最佳"方案,只有"适合业务"的方案。
高可用的核心之一是判断当前状态——谁活着?谁该接管?
但讽刺的是:状态决策本身无法自举。
如果决策者也需要状态决策,那就陷入无限递归。
独裁式
上报者 A ──┐ 上报者 B ──┼──▶ 决策者 ──▶ 决策 上报者 C ──┘
单一决策者,决策高效。但决策者本身是单点故障。
协商式
Server A ◀───连接────▶ Server B │ │ └──────协商决策─────────┘
通过连接交换信息,按规则决策。两台机器协商主备关系。
致命问题:连接断开时怎么办?
民主式
投票轮询 → 多数者胜出 A ◀──▶ B ◀──▶ C
每个节点互通信息,通过投票选出主节点。
致命问题:脑裂——网络分区后,两个子集群各自选举,产生两个主节点。
民主式决策通过"获得过半票数才能当选"来防止脑裂:
5节点集群:需要 3 票才能当选 分区后: - 分区1(3节点):3 >= 3 ✓ 选出主 - 分区2(2节点):2 < 3 ✗ 无法选举
这个规则解决了脑裂,但代价是降低了可用性——当节点故障导致可用节点不足时,系统彻底不可用,而不是降级。
协商式决策依赖心跳来检测对方存活,但心跳本身不可靠:
| 心跳中断原因 | 实际状态 |
|---|---|
| 对方真的挂了 | 需要切换 |
| 网络抖动 | 假故障 |
| 心跳本身丢包 | 假故障 |
| 自己的网络卡 | 误判 |
无法区分"对方挂了"和"网络断了"——这两种情况的正确应对完全不同。
策略1:保守降级
策略2:过半数裁决
策略3:红黄蓝灯机制
红线(立即切换):对方明确声明故障 黄灯(延迟观察):心跳超时,等待确认 蓝灯(保持现状):网络抖动,不做动作
复杂但更健壮。
| SLO | 年停机时间 | 实现难度 |
|---|---|---|
| 99% | 3.65 天 | 简单 |
| 99.9% | 8.76 小时 | 中等 |
| 99.99% | 52 分钟 | 困难 |
| 99.999% | 5 分钟 | 极高 |
每提高一个 9,成本可能翻倍。先问自己:业务真的需要这么高可用吗?
画出现有架构图,标记每个组件的"唯一性":
但不要为不存在的流量担忧。过度设计比欠设计的代价更高。
当故障发生时:
❌ 争取完美:系统全部功能必须正常 ✅ 接受降级:核心功能正常,非核心功能暂时不可用
微博热搜挂了不影响发微博。支付失败了可以提示重试。
把故障限制在局部,不要扩散:
高可用的核心矛盾在于:故障不可避免,但我们需要系统"看起来"永远可用。这个矛盾的解法——冗余——本身引入了状态同步、状态决策、一致性保障等复杂性。
关键认识:
没有银弹。只有理解了这些复杂性的来源,才能做出明智的架构决策。