同城双机房之间相距 30 公里,光纤专线延迟 1.2ms,看起来是理想的容灾距离。某年夏天,市政施工挖断了主干光缆,两个机房同时失联——因为那两条"物理隔离"的专线,实际上走了同一条管道沟。这不是极端的巧合,而是跨机房容灾设计中最常犯的错误:把"地理上的两个机房"误当成"两个独立的故障域"。
跨机房容灾(Geo-Redundancy / DR Site)要解决的是机房级甚至地域级故障:断电、火灾、网络中断、自然灾害、运营商故障。它的技术难度不在于"把数据复制过去",而在于在广域网的不确定延迟下,如何界定一致性、如何决策切换、以及如何证明它真的能用。
一、先确定容灾等级与指标
在动手之前必须回答三个问题,它们决定了整个方案的形态与成本:
- RPO(恢复点目标):机房整体失效时,能接受丢多少数据?
- RTO(恢复时间目标):多久之内必须恢复服务?
- 故障域边界:要抵御的是单机故障、单机房故障,还是单地域故障?
| 容灾形态 | 抵御范围 | 典型 RPO | 典型 RTO | 相对成本 |
|---|---|---|---|---|
| 同机房双机 | 单机、单电源、单机柜 | 0 ~ 秒 | 秒 ~ 分钟 | 低 |
| 同城双机房 | 单机房、单运营商 | 0 ~ 分钟 | 分钟 ~ 30 分钟 | 中 |
| 两地三中心 | 单地域、城市级灾害 | 秒 ~ 分钟 | 30 分钟 ~ 数小时 | 高 |
| 异地冷备(备份站点) | 地域级灾害 | 小时 ~ 24 小时 | 数小时 ~ 数天 | 低 ~ 中 |
成本说明:上表为相对量级比较,具体支出受机房距离、专线带宽、机型与租期影响极大,需按实际配置测算,本文不给出具体金额。
1.1 故障域的核查要点
选第二个机房时,必须逐项确认以下"独立性",任何一项不独立都会让容灾形同虚设:
- 电力:是否接入不同变电站?是否有独立的柴油发电与供油协议?
- 网络:专线是否走不同物理路由(不同管道沟、不同方向出城)?上游运营商是否不同?
- 制冷与消防:是否独立的空调系统与消防分区?
- 运维与管理:是否会被同一次误操作同时影响(例如同一个自动化脚本下发到两个机房)?
- 供应商:是否同一家 IDC / 云厂商的同一地域内的不同可用区?可用区之间通常共享部分基础设施。
二、数据复制:三种模式的取舍
跨机房数据复制的核心矛盾是:延迟放大了"一致性"与"可用性"之间的冲突。同城 1-3ms 尚可接受同步复制,跨城 30ms 以上就必须做取舍。
2.1 同步复制(强一致)
主库提交事务前必须等待备机房确认。优点 RPO=0,缺点是写延迟直接叠加一个 RTT(往返时延),且备机房网络抖动会直接拖垮主库。适用:同城、专线质量极高、写量不大。
# MySQL 半同步复制(RPO≈0 的常用折中) # 主库安装并启用 mysql -e "INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';" mysql -e "SET GLOBAL rpl_semi_sync_master_enabled = 1;" mysql -e "SET GLOBAL rpl_semi_sync_master_timeout = 1000;" # 毫秒 mysql -e "SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1;" # 备库启用 mysql -e "INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';" mysql -e "SET GLOBAL rpl_semi_sync_slave_enabled = 1;" mysql -e "STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;" # 观察半同步状态与退化次数(Rpl_semi_sync_master_no_tx 增长说明在退化) mysql -e "SHOW STATUS LIKE 'Rpl_semi_sync_master_%';"
关键判断:Rpl_semi_sync_master_timeout 超时后半同步会自动退化为异步,此时 RPO 不再为 0。因此必须监控 Rpl_semi_sync_master_no_tx(退化为异步的事务数)与 Rpl_semi_sync_master_yes_tx 的比值,一旦 no_tx 持续上升,说明网络质量已不满足容灾目标。
2.2 异步复制(最终一致)
主库不等待备机房确认,RPO 等于复制延迟。优点是主库性能不受影响、备机房故障不影响生产;缺点是机房级故障时必然丢数据。适用:跨城、写量大、RPO 分钟级可接受。
# 备机房观测复制延迟(RPO 实测依据)
mysql -e "SHOW SLAVE STATUS\G" | grep -E "Seconds_Behind_Master|Slave_IO_Running|Slave_SQL_Running|Last_IO_Error"
# 连续采样 10 分钟取延迟峰值
for i in $(seq 1 60); do
mysql -N -e "SHOW SLAVE STATUS\G" | awk '/Seconds_Behind_Master/{print $2}'
sleep 10
done | sort -n | tail -3
# 网络质量基线测试(判断同步复制是否可行)
ping -c 100 -i 0.2 10.1.0.5 | tail -3
iperf3 -c 10.1.0.5 -t 30 -P 4
判断标准:若 RTT P99 稳定低于 3ms 且丢包率为 0,可考虑半同步;若 RTT 超过 10ms 或有抖动,必须走异步并接受分钟级 RPO。
2.3 文件与对象层复制
数据库之外的静态文件、上传内容,通常用存储层复制而非数据库复制:
# 方案 A:rsync + 硬链接多版本(适合中小规模,成本极低)
rsync -az --delete --bwlimit=20480 \
--link-dest=/backup/www/$(date -d yesterday +%F)-0200/ \
-e "ssh -i /root/.ssh/id_ed25519_dr -o BatchMode=yes" \
/var/www/html/ druser@10.1.0.9:/backup/www/$(date +%F)-0200/
# 方案 B:对象存储跨地域复制(由云厂商托管,配置保留策略)
# 开启版本控制 + 对象锁定(WORM),抵御误删除与勒索加密
# 方案 C:分布式文件系统/块设备复制(DRBD 等),适合强一致要求
# 注意:DRBD 的同步协议 C 等价于同步复制,跨城时写延迟会显著放大
# 传输后校验
sha256sum -c /backup/www/$(date +%F).sha256
三、故障切换:最难的不是技术,是决策
跨机房切换的最大风险是误判:主机房只是网络抖动,却误以为整体失效而切换,导致脑裂与数据双写。因此切换机制必须包含"确认"与" fencing(隔离旧主)"两个环节。
3.1 切换决策的检查清单
- 多源确认:至少两个独立的探测点(不同运营商、不同城市)都判定主机房不可达,且持续超过阈值(建议 3-5 分钟)。
- 区分网络分区与机房失效:如果备机房能连上主机房的带外管理(IPMI/iDRAC)或云 API,说明可能是网络分区而非机房失效。
- Fencing 旧主:切换前必须通过带外管理或云 API 将主机房的数据库服务强制停止/隔离,防止旧主恢复后继续写入造成双写。
- 记录切换时刻的位点:用于事后数据比对与回补。
- 明确决策人:自动切换需预先定义触发条件与人工兜底流程;禁止"谁先发现谁决定"。
3.2 切换执行流程(以 DNS + 数据库为例)
# 1. 停止备机房复制,提升为新主
mysql -e "STOP SLAVE;"
mysql -e "RESET SLAVE ALL;"
mysql -e "SHOW MASTER STATUS;" # 记录位点,写入事故记录
# 2. 确认数据完整(与预期 RPO 对比)
mysql -e "SELECT COUNT(*), MAX(updated_at) FROM appdb.orders;"
# 3. 应用层指向新主(配置中心下发或改 hosts/连接池配置)
sed -i 's/10.0.0.5/10.1.0.5/' /etc/app/database.yml
systemctl restart app
# 4. 切换流量:DNS 或全局负载均衡
# DNS 方式务必预先把 TTL 调到 60 秒以内,否则生效极慢
dig +short www.example.com
# 云解析 API 修改记录(示意)
# aliyun alidns UpdateDomainRecord --RecordId xxx --RR www --Value 10.1.0.100
# 5. Fencing 主机房(关键!防止恢复后双写)
ipmitool -I lanplus -H 10.0.0.50 -U admin -P '***' chassis power off
# 或通过云 API 停止主机房实例 / 移除其安全组出网权限
# 6. 业务冒烟验证
curl -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://www.example.com/health
mysql -e "SELECT COUNT(*) FROM appdb.orders WHERE created_at >= NOW() - INTERVAL 5 MINUTE;"
3.3 回切(Failback)比切换更危险
主机房恢复后,不能直接把流量切回去——因为主机房的数据是旧的。正确顺序是:先把主机房作为从库接入新主,追平数据,确认一致后再切回。整个过程需要在低峰期进行,且全程保留回退方案。
# 回切:主机房作为从库追平新主
mysql -e "CHANGE MASTER TO MASTER_HOST='10.1.0.5', MASTER_USER='repl',
MASTER_PASSWORD='***', MASTER_AUTO_POSITION=1;"
mysql -e "START SLAVE;"
mysql -e "SHOW SLAVE STATUS\G" | grep -E "Seconds_Behind_Master|Slave_IO_Running"
# 延迟为 0 且稳定后,在低峰期反向切换
pt-table-checksum --host=10.1.0.5 --databases=appdb # 比对一致性
四、恢复验证:证明方案真的能用
跨机房容灾最大的敌人是"长期不用的链路悄悄失效"。验证必须制度化:
| 验证层级 | 频率 | 内容 | 停机影响 |
|---|---|---|---|
| 链路健康检查 | 每日(自动) | 复制延迟、专线质量、备机存活 | 无 |
| 数据可恢复性验证 | 每周(自动) | 备机房还原备份到隔离实例并抽样校验 | 无 |
| 只读切换演练 | 每月 | 把读流量切到备机房,验证备机可服务 | 极低 |
| 完整切换演练 | 每半年 | 低峰期真实切换全量流量,验证 RTO | 有,需公告 |
#!/bin/bash
# /usr/local/bin/dr_verify.sh —— 每日容灾链路自检
set -euo pipefail
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LOG=/var/log/dr_verify.log
ALERT=ops@example.com
{
echo "=== $(date '+%F %T') DR verify ==="
# 1. 复制状态
mysql -e "SHOW SLAVE STATUS\G" | grep -E "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Last_Error"
# 2. 专线质量
ping -c 20 -i 0.2 10.1.0.5 | tail -2
# 3. 备机房服务可达性
curl -sS -o /dev/null -w "dr-site:%{http_code} %{time_total}s\n" https://dr.example.com/health
# 4. 最新备份存在且校验通过
LATEST=$(ls -t /backup/mysql/all-*.sql.gz | head -1)
sha256sum -c "$LATEST.sha256"
} >> "$LOG" 2>&1 || echo "DR VERIFY FAILED, see $LOG" | mail -s "DR alert" "$ALERT"
4.1 演练必须产出的四个数字
- 实际 RPO:备机房数据最新时间戳与切换时刻的差值。
- 实际 RTO:从宣布切换到冒烟验证通过的墙钟时间。
- 数据完整率:抽样校验通过项占比,要求 100%。
- 步骤成功率:Runbook 中无需修正即可执行的步骤占比,低于 90% 需重写。
小结
跨机房容灾的设计次序是:先界定故障域与 RPO/RTO,再选择复制模式(同城可用半同步,跨城必须异步并接受分钟级 RPO),然后设计带 Fencing 的切换流程,最后用分级演练制度保证链路长期有效。真正的难点从来不是"把数据复制过去",而是在网络分区面前做出正确决策、并确保回切时不会因为数据倒流造成二次事故。
避坑清单
- 两个机房必须核查电力、网络路由、运营商、消防是否真正独立,共沟光缆是高频陷阱。
- 半同步复制超时会自动退化为异步,必须监控
Rpl_semi_sync_master_no_tx。 - 切换前必须 Fencing 旧主,否则旧主恢复后会造成双写。
- DNS 切换前务必提前把 TTL 调到 60 秒以内,否则生效极慢。
- 回切比切换更危险:必须先把主机房作为从库追平,再低峰期反向切换。
- 容灾链路必须每日自检,长期不用会静默失效。
- 演练要产出实际 RPO/RTO 并与目标对比,不达标就改设计而不是改目标。
企业QQ咨询




