MPLS 专线抖动致跨机房数据库同步中断的定位

跨机房 MPLS 专线时延突增丢包,主从数据库同步线程报错中断,业务读写分离出现数据不一致。

一、问题背景

我们的核心交易库采用"主机房 A + 备机房 B"跨机房主从架构:A 机房为主(读写),B 机房为从(只读报表/容灾),通过 MySQL 原生的主从复制(基于 binlog 的异步复制)跨机房同步。A、B 两机房之间走一条运营商 MPLS 专线(专线网关为 A 侧 10.0.0.1、B 侧 10.0.0.2,互联地址段 10.0.0.0/30),业务读写分离由中间件按"主写从读"路由。

2025 年 10 月 9 日上午,报表团队反馈 B 机房查到的数据与 A 机房对不上,随后复制监控告警。

二、故障现象

  1. 10:30 起,B 机房从库 Slave_IO_Running 变为 No,复制线程中断;
  2. Seconds_Behind_Master 在中断前一度飙到 120s 以上,随后线程挂掉;
  3. 业务侧读写分离出现数据不一致:用户在 A 机房刚下的单,在 B 机房报表里查不到;
  4. 从库错误日志反复出现连接主库超时、重试失败:
1
2
[ERROR] Slave I/O: error connecting to master '[email protected]:3306' - retry-time: 60 retries: 86400, Error_code: 2013 (Lost connection to server during query)
[ERROR] Slave I/O: Got timeout reading communication packets
  1. 但 A 机房主库本身健康,本地读写无异常;B 机房到公网、到其他内网段正常,唯独到 A 机房专线时好时坏。

三、排查过程

第一步:确认是网络问题还是数据库问题。 在 B 机房从库机器上对主库 IP 做连续 ping 与 mtr:

1
2
3
4
ping -c 20 10.0.0.1
# 64 bytes from 10.0.0.1: icmp_seq=12 ttl=63 time=1823 ms
# 64 bytes from 10.0.0.1: icmp_seq=13 ttl=63 time=*  (丢包)
# --- 10.0.0.1 ping statistics --- 20 packets transmitted, 15 received, 25% packet loss

平时该专线 RTT 在 3–5ms,此刻已到 1.8s 且 25% 丢包,明显是专线质量劣化。再看 mtr 路径:

1
2
3
4
mtr -r -c 30 10.0.0.1
# Host   Loss%  Snt  Avg  StDev
# 10.0.0.2  0.0%  30   0.4  0.2   (B 侧网关正常)
# 10.0.0.1 25.0%  30 1823  900    (A 侧网关抖动)

抖动发生在跨机房 MPLS 这一段,而非本地。

第二步:确认抖动特征。 持续 5 分钟抓 RTT 分布,发现是周期性突发:每约 40 秒出现一次 1–2 秒的时延尖峰并伴随丢包,低谷期又恢复正常。这种"规律性抖动"典型是运营商侧 MPLS 链路做了某种重路由或存在微突发拥塞。

第三步:核对带宽与 QoS。 登录两侧专线网关查接口统计:

1
2
3
4
5
show interfaces TenGigE0/0/0/1
# input rate 8.2 Gbps, output rate 7.9 Gbps (专线带宽 10G)
# 输错: input errors 0, CRC 0, but "input drops" 累计上涨
show policy-map interface TenGigE0/0/0/1 output | inc drop
#  class-default:  drop 18423 packets  (QoS 默认类丢包)

发现默认类有持续丢包,说明瞬时流量逼近 10G 带宽上限,突发时被丢弃——这也解释了复制线程在大数据事务(如批量报表回放)时被卡断。

第四步:关联变更。 联系运营商后确认,10:25 其对该 MPLS 链路做了一次保护倒换演练(未提前充分通知),部分流量被临时切到备用 LSP,路径变长、Buffer 不足,导致微突发丢包。

四、解决方案

  1. 先恢复复制:在 B 机房从库手动重启复制线程,并临时调大复制相关超时,避免瞬时抖动再次秒断:
1
2
3
4
5
6
STOP SLAVE;
CHANGE MASTER TO MASTER_CONNECT_RETRY=10, MASTER_RETRY_COUNT=86400;
START SLAVE;
-- 同时调大从库 net_read_timeout / net_write_timeout
SET GLOBAL net_read_timeout=120;
SET GLOBAL net_write_timeout=120;
  1. 数据库层加复制心跳,让中断更快被发现、连接更早重建:
1
2
-- 主库
CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=2;
  1. 网络层临时规避:与运营商确认保护倒换演练窗口,将其避开业务高峰;同时对关键复制流量打 MPLS EXP/QoS 高优先级标签,避免被默认类丢弃。
  2. 带宽扩容评估:将专线从 10G 临时升级保障,错峰跑批量报表,降低瞬时拥塞。

恢复后 Seconds_Behind_Master 从 120s 逐步回落到 0,数据一致性在约 15 分钟后追平。

五、根因分析

根因是跨机房 MPLS 专线出现周期性抖动+微突发丢包,击穿了异步复制链路的健壮性

  • 运营商保护倒换演练使部分流量临时走绕路 LSP,路径 RTT 从 3ms 涨到 1.8s,Buffer 不足引发丢包;
  • MySQL 异步复制的 IO 线程对网络中断敏感,默认 net_read_timeout 较短,丢包导致 binlog 拉取中断即报错退出;
  • 复制线程挂掉后,写入仍在 A 机房进行,B 机房数据持续滞后,读写分离架构下用户读到陈旧数据;
  • 专线接口默认类 QoS 在带宽逼近上限时丢弃复制包,没有为数据库复制流量预留高优先级通道。

本质是跨机房强一致依赖(复制)跑在一条"无 QoS 保障、又会发生抖动"的单链路上,缺乏超时容错与流量分级。

六、预防措施

  1. 复制参数加固:从库设置合理的 MASTER_CONNECT_RETRYnet_read_timeout/net_write_timeout,并开启 MASTER_HEARTBEAT_PERIOD,让抖动后能快速自愈而非长期挂死。
  2. 专线 QoS 分级:为数据库复制、存储同步等跨机房关键流量打高优先级 MPLS EXP 标签,保证其在拥塞时不被默认类丢弃。
  3. 双专线/多路径:关键机房间部署主备两条异构运营商专线,配合 BFD 快速检测 + 动态路由切换,单链路抖动自动切备用。
  4. 变更协同机制:要求运营商任何 MPLS 倒换、演练必须提前通知并避开业务高峰,纳入变更窗口管理。
  5. 一致性校验与告警:部署 pt-table-checksum 定期比对主从差异;对 Slave_IO_Running=NoSeconds_Behind_Master 超阈值做秒级告警,避免滞后被业务先发现。
  6. 读写分离降级:当检测到从库延迟过大时,中间件自动把读请求切回主库,牺牲部分性能换取一致性。

七、总结

这次故障是典型的"网络抖动用数据一致性买单":一条 MPLS 专线的保护倒换演练,通过 MySQL 异步复制的脆弱连接,传导成了跨机房数据不一致。

排查路径很清晰——从库复制报错 → 网络层对照 ping/mtr 定位专线抖动 → 网关接口统计确认 QoS 丢包 → 关联运营商变更,一线工程师只要按顺序下钻就能锁定。更深的启示是:跨机房复制这类"看似数据库、实则强依赖网络"的链路,必须在网络侧做 QoS 分级、多路径容灾,在数据库侧做超时与心跳加固,双管齐下才能扛住底层链路的日常抖动。

使用 Hugo 构建
主题 StackJimmy 设计