主从复制在跨机房场景下默认不可靠,因MySQL异步复制不校验从库落盘,高延迟下Seconds_Behind_Master严重失真甚至恒为0,IO线程可能卡在TCP重传;主库崩溃会导致未同步binlog永久丢失。

主从复制在跨机房场景下为什么默认不可靠
因为 MySQL 默认的异步复制不校验从库是否真正落盘,网络延迟高时,Seconds_Behind_Master 会严重失真,甚至长时间显示 0 —— 实际上从库 IO 线程早卡在 TCP 重传里了。更麻烦的是,主库 crash 后,未同步到从库的 binlog 就永远丢失。
- 跨机房 RTT 常在 20–80ms,远高于同机房的
-
SHOW SLAVE STATUS中的Seconds_Behind_Master只对比主库写入时间戳和从库 SQL 线程执行时间戳,不反映网络传输耗时 - 从库
relay_log_space_limit设得太小(比如默认 0),IO 线程堆积大量未读 relay log,进一步掩盖真实延迟
必须开启 semi-sync 复制并调优超时参数
semi-sync 不是银弹,但它是跨机房容灾的底线。关键不是“开了就行”,而是要让超时逻辑贴合你的网络抖动特征。
- 主库配置:
rpl_semi_sync_master_enabled = ON,rpl_semi_sync_master_timeout = 1000000(单位微秒,即 1s)—— 太短会频繁退化为异步,太长则主库写入阻塞太久 - 从库配置:
rpl_semi_sync_slave_enabled = ON,且确保slave_net_timeout≥rpl_semi_sync_master_timeout / 1000000 + 1(比如主设 1s,从库slave_net_timeout至少设为 2s) - 必须监控
Rpl_semi_sync_master_no_tx和Rpl_semi_sync_master_yes_tx,比值持续升高说明 semi-sync 经常失败退化
用 GTID + 延迟从库做故障切换兜底
即使开了 semi-sync,也不能假设从库时刻可接管。真实故障中,你往往只有几十秒窗口判断哪台从库最“新”——GTID 是唯一靠谱依据。
- 主从必须统一开启
gtid_mode = ON和enforce_gtid_consistency = ON,否则SELECT MASTER_POS_WAIT()和WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS()都不可靠 - 至少部署一台
CHANGE MASTER TO ... MASTER_DELAY = 3600的延迟从库,它不参与 semi-sync,但能防止误删/误更新被立刻传播 - 切主前,用
SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS('xxx-yyy-zzz:12345')等待指定 GTID 执行完成,而不是依赖Seconds_Behind_Master
网络层必须绕过默认 TCP 栈瓶颈
MySQL 复制走的是普通 TCP 连接,而跨机房链路丢包率稍高(0.1%–1%),Linux 默认的 tcp_retries2=15 会导致单次重传最长等 15 分钟,直接卡死 IO 线程。
- 在复制专用网卡上启用
tcp_fastopen和调低tcp_retries2 = 6(对应约 13 秒超时),避免无限等待 - 禁用 Nagle 算法:
SET GLOBAL slave_compressed_protocol = OFF并在 my.cnf 的[client]段加tcp-nodelay(部分版本需 patch 客户端) - 不要复用业务网络:主从之间用独立物理链路或 VLAN,避免
netstat -s | grep "retransmitted"持续上涨
跨机房复制真正的复杂点不在 MySQL 配置本身,而在你能否把网络抖动、内核重传、GTID 一致性这三层耦合问题拆开验证。随便改一个 timeout 参数之前,先抓包看 TCP Retransmission 是否真的发生了。










