
我们在香港落地一个游戏数据平台,使用 MySQL 构建核心业务库,主从架构+读写分离方案本是常规部署,但在用户激增阶段,我们遇到两个明显的瓶颈:
- 主库写入放大(Write Amplification)导致 IOPS 飙升,即便使用了高性能 NVMe 也开始频繁告警。
- 从库同步延迟不断积压,造成部分读流量命中过期数据,影响了推荐、排行榜等功能的时效性。
我将复盘整个调优过程,详细讲述我们是如何在香港本地服务器中,结合 MySQL 参数优化、binlog 格式选择、并发复制机制、以及物理层 IO 策略,实现 写入放大减半 和 复制延迟压缩 90% 以上 的。
一、主从复制瓶颈的初步诊断
1. 硬件环境(香港 A5 高性能服务器)
- 主库配置:32C64G + NVMe SSD(RAID10)
- 从库配置:16C32G + SATA SSD
- MySQL 版本:8.0.34
- 网络:香港本地 BGP 内网互通,延迟 < 1ms
2. 复制延迟初步观测
我们通过以下命令持续监控复制状态:
SHOW SLAVE STATUS\G
发现 Seconds_Behind_Master 不稳定,平均在 3~10 秒,有时甚至超过 20 秒。Relay_Log_Space 不断增加,说明从库的 SQL 线程处理速度跟不上 IO 线程。
3. 主库写放大现象分析
在启用 performance_schema 后,我们通过以下查询分析了 innodb 的写入情况:
SELECT * FROM sys.io_global_by_file_by_bytes;
我们发现:
- 每秒物理写量高达 150MB+
- 每 1 条业务写入操作,在底层可能触发了 8~12 次磁盘 IO
- 特别是小事务大量并发时,binlog 写入频繁、刷盘开销巨大
二、优化方案概览
| 优化方向 | 实施策略 | 效果 |
|---|---|---|
| 写放大优化 | 批量写入、压缩事务、延迟刷盘 | 主库 IOPS 降低 40% |
| 复制延迟压缩 | 并发复制、GTID 启用、减少锁争用 | 延迟从 10s 降到 < 1s |
| 物理层优化 | 调整 binlog/redo 刷写策略,使用 O_DIRECT | 磁盘写放大收敛 |
| 网络层优化 | 从库与主库使用 BGP 内网,启用压缩 | binlog 同步吞吐提升 |
三、MySQL 主库写入放大优化实操
1. 启用延迟刷盘:innodb_flush_log_at_trx_commit=2
我们最先改动的是刷盘策略。原配置为 1,即每次提交事务都刷盘,虽然最安全,但 IO 放大严重。我们改为:
innodb_flush_log_at_trx_commit = 2
sync_binlog = 0
这让 redo 和 binlog 都变为异步刷盘,风险可接受(我们还有高频快照和备份策略)。
效果:主库的写入 TPS 提升了约 30%,物理写入下降明显。
2. 批量写入替代单条 INSERT
之前业务大量为单行 insert:
INSERT INTO events (uid, type, time) VALUES (1001, 'login', now());
我们改为每 N 条聚合后批量写入:
INSERT INTO events (uid, type, time) VALUES
(1001, 'login', now()),
(1002, 'logout', now()),
(1003, 'pay', now());
改造中间件逻辑后,将写入频率压缩到原来的 30%。
3. 使用 ROW 代替 STATEMENT binlog 模式
虽然 STATEMENT 写入更少,但在高并发下产生大量 unsafe statement,影响复制一致性。我们统一为:
binlog_format = ROW
binlog_row_image = MINIMAL
MINIMAL 模式能进一步降低 binlog 大小,只记录变更字段。
四、MySQL 从库复制延迟压缩实操
1. 启用 GTID 和并发复制线程
gtid_mode = ON
enforce_gtid_consistency = ON
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 8
开启逻辑时钟并发复制后,从库能并行应用多个事务(只要它们不冲突),吞吐提升显著。
2. 从库启用延迟提交
relay_log_recovery = 1
relay_log_info_repository = TABLE
确保复制状态不会因故障丢失,提升同步稳定性。
3. 使用 semi-sync 半同步复制
通过插件启用:
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
确保主库事务提交后至少有一个从库 ACK,可以缓解延迟数据读取问题。
五、物理层优化与网络协同
1. 文件系统层:启用 O_DIRECT 减少双缓存
innodb_flush_method = O_DIRECT
减少 write 和 fsync 的重复缓存,适合我们这种 NVMe 环境。
2. binlog 压缩与网络内网优化
MySQL 8.0 开始支持 binlog 压缩,我们启用后效果显著:
binlog_transaction_compression = ON
加之我们在香港数据中心采用 BGP Anycast + 专线互通,从库与主库网络 RTT < 0.5ms。
六、优化效果对比(部署前 vs 优化后)
| 项目 | 优化前 | 优化后 |
|---|---|---|
| 主库 IOPS | 11,500 | 6,700 |
| binlog 大小 | 14GB/天 | 6.2GB/天 |
| 从库延迟 | 平均 8~12 秒 | 稳定 < 1 秒 |
| TPS 峰值 | 9,200 | 12,800 |
| 数据一致性 | 存在秒级差异 | 基本实时 |
七、经验技巧
MySQL 主从复制并不是配置完就能跑的架构,尤其在写入高峰时段,如果主库写放大问题不处理,从库延迟只会雪上加霜。
写入压缩策略和 binlog 优化是关键突破口,而并发复制才是处理高吞吐下延迟的终极武器。
如果你也在香港部署数据库服务,别忘了利用好本地低延迟网络、IO 优化能力,结合 MySQL 8.0 新特性,可以带来意想不到的稳定性提升。











