网络瓶颈的判断依据是retrieved_gtid_set与executed_gtid_set差距小但seconds_behind_master持续偏高,表明io线程未及时获取binlog;需结合mtr丢包/抖动、iftop吞吐、slave_io_running状态综合验证。

怎么看网络是不是瓶颈:先盯住 Seconds_Behind_Master 和 Retrieved_Gtid_Set 的差值
单纯看 Seconds_Behind_Master > 0 并不能说明是网络问题——它可能只是从库 SQL 线程慢。真正指向网络瓶颈的信号是:Retrieved_Gtid_Set(已拉取的 GTID)和 Executed_Gtid_Set(已执行的 GTID)之间差距很小,但 Seconds_Behind_Master 却持续偏高。
这意味着从库 IO 线程“没拿到新 binlog”,不是拿来了不会跑,而是根本没传过来。此时再结合网络工具验证:
- 用
mtr持续测主从间丢包率和抖动,>0.5% 丢包或 >5ms 抖动就值得怀疑 - 用
iftop -P 3306观察主从连接的实时吞吐,对比主库binlog写入速率(SHOW MASTER STATUS隔 10 秒两次,算文件增长量) - 检查
SHOW SLAVE STATUS\G中的Slave_IO_Running: Yes是否稳定,频繁Connecting或Waiting for master to send event是典型网络不稳定表现
怎么估算真实需要的带宽:别只看峰值,要看 binlog 流量密度
主库每秒写入多少 binlog,直接决定网络最低吞吐下限。ROW 格式下,一条 UPDATE 可能生成几 KB 日志,尤其涉及大字段或 JSON 类型时。
实操建议用以下方式粗估:
- 在主库执行
SELECT SUM(LENGTH(event_info)) FROM performance_schema.events_statements_history_long WHERE event_name LIKE 'statement/sql/%' AND timer_start > UNIX_TIMESTAMP(NOW() - INTERVAL 60 SECOND) * 1000000000;(仅作参考,实际 binlog 更大) - 更准的做法:监控
mysql-bin.0000xx文件 1 分钟内增长字节数,除以 60,得到平均 B/s;再乘以 1.3(留余量)→ 就是最低要求带宽 - 若结果 > 50MB/s(即 400Mbps),而主从走的是千兆共享交换机,基本可以判定带宽已饱和
启用压缩后为什么延迟没降?检查 slave_compressed_protocol 和 MySQL 版本兼容性
MySQL 8.0.20+ 才完整支持 zstd 压缩,但默认不开启,且依赖客户端协议协商。常见踩坑点:
-
slave_compressed_protocol=ON必须在从库my.cnf中显式配置并重启,动态 SET 不生效 - 主库必须运行在 8.0.20+,否则即使从库支持,dump 线程也不会发起压缩协商
- 压缩效果受数据可压缩性影响极大:大量二进制 blob、加密字段、已经 gzip 过的内容,zstd 压缩率可能不足 10%,白开
- 启用后务必验证:执行
SHOW SLAVE STATUS\G,确认Slave_IO_State中出现Waiting for master to send event (compressed)
跨机房部署时,TCP 参数比压缩更重要
当主从物理距离超过 50km(比如同城双活),RTT 常超 2ms,此时 TCP 自适应窗口和重传机制会成为隐性瓶颈,比压缩更关键。
推荐在从库所在服务器上调整:
-
net.ipv4.tcp_window_scaling = 1(确保大窗口启用) -
net.ipv4.tcp_rmem = "4096 262144 16777216"(增大接收窗口,适配高带宽高延迟链路) -
net.ipv4.tcp_sack = 1(启用选择性确认,减少丢包重传开销) - 避免在中间网络设备上开启“TCP 优化”类功能(如某些 SD-WAN 设备的 ACK 合并),它们会破坏 MySQL dump 线程的流控节奏
这些参数改完后,用 ss -i 查看连接的实际 cwnd 和 rtt,确认是否提升。很多团队调了压缩却忽略这点,结果延迟纹丝不动。











