Appearance
第 15 讲|高可用和容灾
高可用(High Availability) 与 容灾(Disaster Recovery) 经常被一起提到,但解决的是不同层次的问题。
| 维度 | 高可用 | 容灾 |
|---|---|---|
| 故障范围 | 局部:单机、单组件、单服务 | 大范围:机房、城市、区域 |
| 应对手段 | 主备、集群、健康检查、自动切换 | 异地备份、跨地域同步、灾备站点 |
| 切换时间 | 秒级到分钟级 | 分钟级到小时级 |
| 数据完整性 | 通常零丢失 | 可能丢失少量数据 |
| 成本 | 中等 | 高(尤其多活) |
简言之:高可用应对"小故障",容灾应对"大灾难"。两者都涉及备份、切换、同步、演练,但影响范围和投入完全不同。
本讲围绕容灾的核心展开:RTO/RPO 指标、备份恢复的工程要求、主备与异地备的差异、同城双活、异地双活、两地三中心、多活架构的风险。
一、RTO 和 RPO:容灾的两个核心指标
容灾方案设计的两个最重要指标:

| 指标 | 含义 | 衡量什么 |
|---|---|---|
| RTO(Recovery Time Objective) | 故障后业务恢复需要多久 | 服务停摆时间 |
| RPO(Recovery Point Objective) | 故障后最多丢失多长时间的数据 | 数据丢失量 |
一个具体例子
某系统每天凌晨 0 点做一次全量备份,上午 10 点数据库损坏:
- 只能恢复到 0 点那份备份 → 0:00 到 10:00 的写入全部丢失,RPO ≈ 10 小时
- 从准备机器、恢复备份到业务可用花了 2 小时 → RTO = 2 小时
RTO 和 RPO 与成本的关系
RTO 和 RPO 越小,成本越高——这是容灾设计的铁律。
| RTO / RPO | 方案 | 相对成本 |
|---|---|---|
| RTO 数小时 / RPO 一天 | 每日备份 + 故障时手工恢复 | 1× |
| RTO 数分钟 / RPO 数分钟 | 主备 + binlog 持续归档 | 5-10× |
| RTO 秒级 / RPO 接近零 | 同城双活 + 同步复制 | 30-50× |
| RTO 秒级 / RPO 零 | 异地多活 + 强一致 | 100×+ |
容灾方案设计的第一步是与业务方对齐目标:
- 这个系统能容忍多久不可用?
- 能容忍丢失多少数据?
根据业务实际承受能力反推架构,而不是盲目追求"零 RPO 零 RTO"。绝大多数业务并不需要那种级别的保障——把所有成本都堆到容灾上,反而拖垮整个系统经济性。
不同业务的合理目标
| 业务类型 | 典型 RTO | 典型 RPO |
|---|---|---|
| 内部低频工具 | 数小时到一天 | 一天 |
| 一般 SaaS 业务 | 数十分钟 | 数分钟到一小时 |
| 电商业务(非交易) | 分钟级 | 秒级 |
| 在线交易、支付 | 秒级 | 接近零 |
| 金融核心 | 秒级 | 零(异步丢失也不可接受) |
二、备份恢复:容灾的底线
备份是容灾的绝对底线——所有更高级的容灾形态(主备、双活、多活)都建立在备份之上。

备份能应对的故障
主备/复制能应对的故障(节点故障、机房故障),备份能应对所有故障,包括:
- 误删数据(
DROP TABLE、DELETE无 WHERE) - 应用 bug 写脏数据
- 勒索病毒加密数据
- 存储损坏
- 主从复制把误操作同步走了
- 配置错误导致数据被覆盖
- 安全事件后数据篡改
这些场景下复制完全无效(因为错误操作会被同步到所有副本),只有从历史时间点的备份才能恢复。
备份不是"做了就行"
要保证备份真正可用,需要确认:
| 维度 | 要确认什么 |
|---|---|
| 频率 | 每小时/每天?决定 RPO 上限 |
| 保留周期 | 保留几天/几周/几个月?决定能恢复到多久之前 |
| 异地保存 | 备份必须跟源数据物理隔离 |
| 权限隔离 | 误删生产的人不能顺手删备份 |
| 加密 | 备份本身要加密,防止泄露 |
| 校验 | 定期验证备份文件完整性 |
| 恢复演练 | 备份能不能真的恢复出来 |
"备份未演练 = 没有备份"
最容易被忽略的是恢复演练。备份文件存在 ≠ 能恢复成功。常见失效情况:
| 失效原因 | 现场表现 |
|---|---|
| 压缩包损坏 | 解压报错 |
| 账号权限不够 | 恢复时无法写入目标位置 |
| 数据库版本不兼容 | 备份是 MySQL 5.7,目标是 8.0 |
| 缺少 binlog | 全量备份能恢复但无法基于时间点恢复 |
| 对象存储跨区域同步未完成 | 异地备份其实还没到位 |
| 加密 key 丢失 | 备份文件无法解密 |
| 备份文件其实是空的 | 备份脚本失败但没人发现 |
这些情况都让"以为有备份"变成"备份用不了"——真正发现问题时,损失已经无法挽回。
恢复演练的标准流程
第 1 步:准备一套与生产隔离的目标环境
第 2 步:从备份系统拉取最新备份文件
第 3 步:在目标环境完整恢复(数据库 + 配置 + 文件)
第 4 步:启动应用连接恢复的数据库
第 5 步:跑关键业务查询,验证数据完整性
第 6 步:对比生产数据,确认恢复点正确
第 7 步:记录恢复耗时、问题、改进点只看"备份任务执行成功"日志远远不够——必须真正恢复出来才算备份有效。建议频率:
- 关键业务系统:每月一次
- 一般业务系统:每季度一次
- 边缘系统:每半年一次
备份的 3-2-1 原则
业界经典的备份原则:
- 3 份数据副本(生产 + 2 份备份)
- 2 种不同存储介质(磁盘 + 对象存储)
- 1 份异地存储
这个原则同时防御了硬件故障、单点存储故障、机房级灾难三类问题。
三、主备与异地备

各种备份形态的对比
| 形态 | 数据同步方式 | RTO | RPO | 成本 |
|---|---|---|---|---|
| 本地主备 | 同步/半同步复制 | 秒级 | 接近零 | 中 |
| 异地备份 | 定期备份传输到异地 | 数小时 | 备份间隔 | 低 |
| 异地冷备 | 异步复制 + 平时不运行业务 | 数十分钟到小时 | 复制延迟 | 中 |
| 异地热备 | 实时同步 + 持续就绪 | 分钟级 | 接近零 | 高 |
| 同城双活 | 同步复制 + 两边都运行 | 秒级 | 零 | 高 |
| 异地双活 | 异步复制 + 两边都运行 | 秒级 | 秒级 | 极高 |
异地备的两个核心问题
数据怎么过去和入口怎么切过去——这两个问题决定异地备的实际效果。
| 问题 | 影响 |
|---|---|
| 数据同步慢 | RPO 大,可能丢失大量数据 |
| 入口切换慢 | RTO 长,业务停摆时间长 |
| 数据同步延迟监控 | 不监控就不知道实际 RPO |
| 入口切换流程未演练 | 真出事时切不过去 |
异地异步复制的 RPO 代价
场景:数据库异步复制到异地机房
14:00:00 主站故障,业务转移到异地
14:00:00 异地数据落后主站 3 分钟
14:00:00 主站 13:57-14:00 的写入,异地没有
后果:
- 这 3 分钟的订单可能丢失
- 用户已经收到的"创建成功"反馈,异地查不到对应订单
- 需要业务侧的补偿、对账、人工处理RPO 不是数字游戏,是实实在在的业务损失——3 分钟数据丢失对支付系统可能意味着数百笔交易要人工对账。
业务对数据敏感时,要用更严格的同步方式:
- 半同步复制 — 主库等至少一个从库确认才提交
- 同步复制 — 主库等所有副本都确认
- 强一致协议(Raft/Paxos)— 多数派确认
代价是写入延迟和性能下降——选择哪种取决于业务对一致性的真实需求。
四、同城双活
同城双活:同一城市的两个机房同时承载业务。
同城双活的特点
| 维度 | 说明 |
|---|---|
| 距离 | 同城内通常几十公里 |
| 网络延迟 | 1-3ms |
| 同步方式 | 可以做同步或半同步复制 |
| 故障覆盖 | 单机房故障、机房网络设备故障、局部停电 |
| 切换时间 | 秒级到分钟级 |
| 数据丢失 | 接近零 |
同城双活解决什么问题
- 单机房硬件故障
- 机房网络中断
- 机房供电故障
- 机房空调失效
- 单机房整体维护
两边平时都接流量,故障时一边接管全部流量,不需要从冷启动拉起——切换时间远短于异地备。
同城双活的难点:数据双活
读多写少的系统比较容易做双活——两边都能查询,写入集中在某一机房就够了。
强一致写入的双活就要看"写入归属"怎么设计——两边同时写同一份数据必然碰到冲突:
| 写入策略 | 含义 | 难点 |
|---|---|---|
| 单写双读 | 写只在一个机房,两边都能读 | 写入机房故障时仍需切换 |
| 双写 + 同步复制 | 两边都能写,通过同步复制保证一致 | 跨机房同步延迟,性能下降 |
| 双写 + 分片 | 数据分片,每片有归属机房 | 工程复杂,跨片操作受限 |
| 双写 + 冲突解决 | 通过 CRDT、最后写入获胜等机制 | 业务侧要适应 |
实际生产中真正做"全部双写"的系统很少,大部分双活是 "读双活 + 单点写"——两边都接读流量,写流量通过路由集中到某一边。
五、异地双活
异地双活:不同城市或不同区域同时承载业务。
异地双活解决什么问题
- 城市级灾难(地震、洪水、大规模停电)
- 区域级故障(运营商网络故障覆盖整个城市)
- 国家级监管要求(某些行业要求数据不能跨境)
- 用户就近接入(全球业务,降低延迟)
异地双活的难点
异地双活的难度远高于同城双活:
| 难点 | 表现 |
|---|---|
| 跨地域延迟 | 几十毫秒到 100ms+,同步操作变得困难 |
| 数据一致性 | 强同步性能不可接受,只能异步 + 业务补偿 |
| 网络成本 | 跨区域专线昂贵 |
| 运维复杂度 | 双倍的环境,部署、监控、变更都要协调 |
| 切换协调 | 多个组件同时切换的协调难度极大 |
单元化:异地双活的现实方案
真正"任意请求打到任意区域"的异地双活极少。更常见的是按某种维度分流(单元化):
| 分流维度 | 工作方式 |
|---|---|
| 按地域 | 华东用户主要访问华东机房,华北用户主要访问华北机房 |
| 按用户 ID 哈希 | 用户固定归属某一区域,数据写入归属区域 |
| 按业务单元 | 不同业务在不同区域,业务间通过 API 互相调用 |
| 按时间 | 不同时段流量切到不同区域(主要用于切流演练) |
单元化的核心思想:让每个用户的写入都在自己归属的单元完成,避免跨单元写冲突。
用户归属切换的复杂度
单元化的代价是用户归属一旦需要变化(用户搬家、业务迁移、灾备切换),涉及的状态同步极其复杂:
- 登录态 — 跨单元 session 不通,需要重新登录
- 缓存 — 用户相关的缓存在哪个单元?
- 订单状态 — 进行中的订单怎么迁移?
- 消息消费位移 — Kafka consumer offset 是单元独立的
- 第三方依赖 — 支付、短信等回调地址需要切换
单元归属切换本身就是个复杂工程,不是 DNS 切一下就完事的。
六、两地三中心
两地三中心是国内传统企业(尤其金融、电信、政务)最常见的容灾形态:

- 同城两个生产中心
- 异地一个灾备中心
各中心的角色
| 中心 | 职责 |
|---|---|
| 同城生产中心 | 承载主要业务流量 |
| 同城灾备中心 | 低延迟接管,处理本地中心故障 |
| 异地灾备中心 | 处理城市级灾难 |
各中心的同步策略
- 同城两中心:距离近,可以做同步或半同步复制(数据几乎不丢)
- 异地中心:距离远,一般做异步复制(可能丢少量数据)
这样组合下来:
- 本地快速切换(应对机房级故障)
- 异地兜底(应对城市级灾难)
"有机房"和"可切换"是两回事
异地灾备最大的认知陷阱:
- 异地机房租了 ✓
- 异地机器装了 ✓
- 异地数据同步了 ✓
- 异地业务从没真正切过 ✗
这种状态下,异地中心只是"有资源",不是"可靠容灾"——真出事时,可能切不过去,或切过去后业务跑不通。
完整的可靠容灾要持续投入:
| 持续工作 | 频率 |
|---|---|
| 数据同步监控 | 实时 |
| 配置同步 | 每次变更 |
| 应用部署同步 | 每次发布 |
| 完整切换演练 | 每年至少 1 次 |
| 部分切换演练 | 每季度 |
| 灾备站点扩容 | 跟生产一起 |
| 灾备人员培训 | 每年 |
异地灾备的运营成本可能比一个普通业务集群还高——但这是真正能用的容灾必须付的代价。
七、多活架构的风险
多活听起来美好(故障无感、性能更好、容灾天然),但实际落地涉及系统的方方面面,每一处都可能成为新故障源。
主要风险点
| 风险 | 表现 |
|---|---|
| 写冲突 | 两个机房同时修改同一数据,合并时不知道以谁为准 |
| 缓存不一致 | 用户在不同机房看到不同状态 |
| 消息重复消费 | 两边都消费同一事件,业务被处理两次 |
| 定时任务重复 | 定时任务在多机房同时跑,发两次邮件、扣两次款 |
| 切换不完整 | 入口切走但后端、数据库、消息队列还在旧链路 |
| Session 跨域 | 用户在 A 机房登录,请求被路由到 B 机房,登录态失效 |
| 跨域调用延迟 | 单元内调用 ms 级,跨单元调用几十毫秒 |
| 数据回流 | 异地的数据要回流到主站做汇总分析 |
容灾演练:必须跑完整业务路径
容灾演练不是"切个 DNS 看能不能 ping 通"——必须跑完整业务路径:
- 用户登录
- 商品查询
- 下单流程
- 支付流程
- 文件上传/下载
- 后台任务
- 报表导出
- 第三方回调
每条主流程都要走一遍,验证切换后的新机房能正常工作。
演练记录要写实际结果
记录格式参考:
演练时间:2026-06-01 02:00
演练范围:全量切到异地灾备中心
实际结果:
02:00 - 触发切换
02:01 - 入口 DNS 切换完成
02:03 - 异地数据库提升为主
02:05 - 应用集群启动,健康检查通过
02:07 - 登录功能恢复 ✓
02:09 - 商品查询恢复 ✓
02:12 - 下单流程恢复 ✓
02:15 - 支付回调失败! 第三方支付的回调地址还指向原主站
02:18 - 手动修改支付回调配置
02:25 - 报表任务失败,异地的 Kafka consumer 没启动
02:30 - 启动 consumer,报表恢复
02:35 - 切回原主站
问题清单:
1. 支付回调地址未纳入切换流程
2. Kafka consumer 在异地需要手动启动
3. 应用启动后 5 分钟才完全 ready,需要优化健康检查这种暴露问题的演练记录,远比"演练成功"四个字有价值——真正暴露问题、推动修复,才是演练的目的。
光说"演练成功"等于没演练,真出事时该踩的坑一个都少不了。
八、容灾的成本-收益评估
不是所有业务都需要高规格容灾。投资容灾前,要做合理的成本-收益评估:
| 业务类型 | 不可用 1 小时的损失 | 合理容灾投入 |
|---|---|---|
| 个人博客 | 几乎零 | 异地备份足矣 |
| 内部工具 | 影响员工效率 | 异地冷备 |
| 一般电商 | 数十万 | 同城主备 + 异地异步备 |
| 大型电商 | 数百万到千万 | 同城双活 + 异地热备 |
| 金融核心 | 数千万+ + 合规处罚 | 异地多活 + 强一致 |
| 关键基础设施 | 难以估量 | 多区域多活 + 持续演练 |
容灾投入的核心问题不是"我能做到多强",而是"我需要做到多强"。盲目追求"零 RTO 零 RPO"会让成本失控,反而拖垮整个系统经济性。
容灾投入的渐进路径
合理的容灾投入是随业务增长渐进的:
阶段 1:本地备份 + 监控告警 (启动期)
阶段 2:数据库主从 + 异地备份 (成长期)
阶段 3:同城主备 + 异地异步备 (扩展期)
阶段 4:同城双活 + 异地热备 (成熟期)
阶段 5:异地多活 + 完整演练体系 (大型化)每一步都解决具体的容灾需求,不要跳过中间阶段直接上多活——多活的工程复杂度极高,小规模团队根本无法运维。
容灾的真正成本不是机器钱
| 成本类型 | 内容 |
|---|---|
| 硬件 | 异地机房、机器、网络专线 |
| 运维 | 异地的部署、监控、变更同步 |
| 人力 | 容灾团队、演练、应急响应 |
| 流程 | 容灾流程的设计、文档、培训 |
| 业务适配 | 应用层为容灾做的改造 |
| 演练时间 | 定期演练对生产的影响 |
| 持续优化 | 业务变化时容灾方案要跟着变 |
机器和带宽只是冰山一角,长期运营成本才是大头。这就是为什么"看起来便宜的容灾方案"在实际运营几年后,总成本可能超过预期数倍。