文章

灾备与容灾方案

灾备与容灾方案

一句话:灾备不是”再搭一套一样的”,而是根据 RTO/RPO 要求选择合适的容灾等级——从定期备份到同城双活到异地多活,成本和恢复能力递增。

容灾等级

等级架构RTORPO成本倍数适用
L1定期备份天级天级1x非核心
L2异地备份小时级小时级1.2x准核心
L3同城主备分钟级秒级2x核心
L4同城双活秒级02x高核心
L5异地双活分钟级秒级3x超核心
L6全球多活00Nx全球服务

数据备份策略

备份层次

L1: 本地快照(秒级,同集群)
  ├── PV 快照
  └── DB 逻辑备份

L2: 同城备份(分钟级,跨 AZ)
  ├── DB 异步复制
  └── 对象存储跨 AZ 复制

L3: 异地备份(小时级,跨 Region)
  ├── DB binlog 同步
  └── 对象存储跨 Region 复制

L4: 冷备份归档(天级,离线介质)
  └── 归档存储 / 磁带

K8s 备份:Velero

# 安装 Velero
velero install \
  --provider aws \
  --bucket velero-backups \
  --backup-location-config region=cn-beijing \
  --snapshot-location-config region=cn-beijing

# 定时备份
velero schedule create daily-backup \
  --schedule="0 2 * * *" \
  --include-namespaces production \
  --ttl 720h  # 保留 30 天

# 恢复
velero restore create --from-backup daily-backup-20260803

# 跨集群迁移
# Cluster A: velero backup create migration-backup --include-namespaces app
# Cluster B: velero restore create --from-backup migration-backup

MySQL 备份恢复

# 全量备份(xtrabackup)
xtrabackup --backup --target-dir=/backup/full \
  --user=root --password=xxx

# 增量备份
xtrabackup --backup --target-dir=/backup/inc1 \
  --incremental-basedir=/backup/full \
  --user=root --password=xxx

# 恢复流程
# 1. 准备全量备份
xtrabackup --prepare --target-dir=/backup/full
# 2. 应用增量
xtrabackup --prepare --target-dir=/backup/full \
  --incremental-dir=/backup/inc1
# 3. 恢复数据
xtrabackup --copy-back --target-dir=/backup/full --datadir=/var/lib/mysql
# 4. PITR(基于 binlog 回放到指定时间点)
mysqlbinlog --start-datetime="2026-08-03 14:00:00" \
  --stop-datetime="2026-08-03 14:05:00" \
  mysql-bin.000123 | mysql -u root -p

同城双活架构

graph TD
    LB[全局负载均衡<br/>DNS/GSLB] --> AZ1[AZ-1<br/>主集群]
    LB --> AZ2[AZ-2<br/>备集群]
    
    AZ1 --> DB1[(MySQL Master<br/>AZ-1)]
    AZ2 --> DB2[(MySQL Slave<br/>AZ-2)]
    DB1 -->|同步复制| DB2
    
    AZ1 --> REDIS1[(Redis Master<br/>AZ-1)]
    AZ2 --> REDIS2[(Redis Slave<br/>AZ-2)]
    REDIS1 -->|异步复制| REDIS2
    
    AZ1 --> ES1[(ES Master<br/>AZ-1)]
    AZ2 --> ES2[(ES Replica<br/>AZ-2)]
同城双活关键设计:
  1. 流量层: GSLB 按权重分流到两个 AZ
  2. 计算层: 两个 AZ 同时服务(Active-Active)
  3. 数据层: MySQL 半同步复制(RPO ≈ 0)
  4. 缓存层: Redis 主从(切换时有秒级数据差异)
  5. 消息层: Kafka 跨 AZ 副本
  
故障切换:
  AZ-1 故障 → GSLB 将流量全切到 AZ-2 → MySQL 提升 Slave 为 Master
  RTO: 1-5 分钟
  RPO: 0(半同步)或秒级(异步)

异地多活架构

graph TD
    GSLB[全局 DNS] --> R1[北京 Region]
    GSLB --> R2[上海 Region]
    
    R1 --> U1[单元1<br/>北京用户]
    R2 --> U2[单元2<br/>上海用户]
    
    R1 --> DSYNC1[数据同步<br/>DTS/Canal]
    R2 --> DSYNC2[数据同步<br/>DTS/Canal]
    DSYNC1 <-->|异步双向| DSYNC2
异地多活(单元化架构):
  1. 按用户维度分片(user_id 路由到单元)
  2. 每个单元自包含(应用 + DB + 缓存)
  3. 跨单元数据异步同步(最终一致)
  4. 单元故障 → 切换到备单元
  
  RTO: 分钟级(DNS 切换 + 数据校验)
  RPO: 秒级(异步同步延迟)
  
核心难点:
  - 数据一致性(跨 Region 延迟大,不能用同步复制)
  - 冲突解决(双写冲突、幂等)
  - 路由正确性(用户必须路由到正确单元)

灾备切换流程

graph TD
    DECISION[决策切换] --> NOTIFY[通知相关方]
    NOTIFY --> STOP1[停止主集群写入<br/>设置只读]
    STOP1 --> SYNC[等待数据同步完成<br/>确认 RPO=0]
    SYNC --> PROMOTE[提升备集群为主<br/>DB failover]
    PROMOTE --> DNS[DNS 切换<br/>指向备集群]
    DNS --> VERIFY[验证服务<br/>SLI 正常]
    VERIFY -->|正常| DONE[切换完成<br/>进入恢复期]
    VERIFY -->|异常| ROLLBACK[回滚<br/>切回主集群]

灾备切换 Checklist

## 灾备切换 Checklist

### 切换前
- [ ] 确认灾备集群数据同步正常
- [ ] 通知所有相关方(开发/业务/客服)
- [ ] 确认切换窗口(低峰期)
- [ ] 准备回滚方案

### 切换中
- [ ] 主集群设置只读(停止写入)
- [ ] 等待数据同步延迟归零
- [ ] 提升灾备 DB 为 Master
- [ ] 更新 DNS / GSLB 指向
- [ ] 验证服务健康(SLI 正常)
- [ ] 验证数据完整性

### 切换后
- [ ] 监控告警确认无异常
- [ ] 反向数据同步配置(备 → 主)
- [ ] 通知恢复完成
- [ ] 安排原主集群修复
- [ ] 回切计划(原集群修复后)

容灾演练

容灾演练频率:
  桌面推演: 每月(纸上谈兵,走流程)
  技术演练: 每季度(实际切换但不切流量)
  全量演练: 每半年(真实切换 + 流量验证)

演练度量:
  - 实际 RTO vs 目标 RTO
  - 实际 RPO vs 目标 RPO
  - 切换成功率
  - 数据一致性验证结果

常见问题 / 坑点

问题原因解决方案
备份没验证过备份了但没恢复测试定期恢复演练
切换后数据不一致异步复制延迟等延迟归零再切换 + 数据校验
DNS 切换太慢TTL 太长短 TTL + 预热 + 多 DNS
多活路由错误用户路由到错误单元路由层 + 数据层双重保障
容灾集群资源不足平时不跑流量定期灌流量验证 + 容量预留

关联知识

参考资源

状态

  • 容灾等级
  • 数据备份策略
  • 同城双活架构
  • 异地多活架构
  • 灾备切换流程
  • 容灾演练