MySQL 主从复制延迟是数据库运维中常见的问题,它可能导致从库数据滞后,影响读写分离场景下的数据一致性。要解决延迟,首先需要理解复制的核心路径:主库将变更写入 binlog,从库的 IO 线程拉取 binlog 并写入 relay log,然后 SQL 线程串行执行 relay log 中的事件。延迟主要发生在 SQL 线程执行阶段,但主库的写入压力、网络传输、从库硬件等也会影响整体延迟。
判断延迟的路径:先定位瓶颈
当发现主从延迟时,不要盲目调参,先通过以下步骤定位瓶颈:
- 查看 Seconds_Behind_Master:通过 SHOW SLAVE STATUS 查看该值,它表示从库 SQL 线程执行落后主库 binlog 的时间(秒)。但注意,该值在无事件执行时可能为 0,且大事务可能造成虚高。
- 检查 IO 线程状态:如果 IO 线程持续忙碌,可能是网络带宽或主库 binlog 写入压力大;如果 SQL 线程忙碌,则可能是从库执行慢。
- 监控主库 binlog 生成速率:通过 SHOW BINARY LOGS 或监控工具查看 binlog 文件增长速率,如果速率远高于从库执行速率,则延迟会持续增加。
- 查看从库的负载:使用 top、iostat 等查看从库 CPU、磁盘 IO,如果从库有其他业务负载,会加剧延迟。
常见原因与解决方案
主库写入压力过大
当主库的 TPS(每秒事务数)很高时,binlog 生成速率可能超过从库 SQL 线程的执行能力。此时,从库的 SQL 线程成为瓶颈。
解决方案:
- 启用并行复制(MTS),让多个 SQL 线程并行执行不同数据库或表的 binlog 事件。MySQL 5.7 支持基于库的并行复制,MySQL 8.0 支持基于 WRITESET 的并行复制,可有效提升从库执行吞吐。
- 如果业务允许,可以对主库进行读写分离,将部分读请求分流到从库,降低主库压力。
- 考虑对热点表进行分库分表,减少单库的写入压力。
大事务导致延迟
一个包含大量行变更的大事务(例如批量更新或删除)在 binlog 中是一个大事件,SQL 线程必须串行执行完整个事务才能提交,期间无法执行其他事务,导致延迟。
解决方案:
- 避免在业务高峰期执行大批量操作,尽量拆分事务,例如每 1000 行提交一次。
- 对于必须的大事务,考虑使用 pt-online-schema-change 等工具进行在线变更,减少锁和复制延迟。
- 调整从库的 binlog 相关参数,例如增大 innodb_buffer_pool_size,提高大事务执行效率。
从库单线程执行限制
在 MySQL 5.6 之前,从库 SQL 线程是单线程的,即使主库是并发写入,从库也只能串行执行。MySQL 5.7 引入了并行复制,但默认关闭。
解决方案:
- 开启并行复制:设置 slave_parallel_workers 大于 0,并根据从库 CPU 核数调整。在 MySQL 5.7 中,可以设置 slave_parallel_type 为 DATABASE 或 LOGICAL_CLOCK;MySQL 8.0 中默认使用 LOGICAL_CLOCK。
- 确保从库的 CPU 和磁盘性能足够,避免因资源不足导致并行复制效率低下。
从库硬件性能不足
从库的磁盘 IO、CPU、内存如果性能较差,执行 binlog 事件的速度就会慢。
解决方案:
- 使用 SSD 替代 HDD,提升随机读写性能。
- 增加内存,扩大 InnoDB 缓冲池,减少磁盘 IO。
- 确保从库的 innodb_flush_log_at_trx_commit 和 sync_binlog 参数设置合理,避免频繁刷盘。但注意,调低这些参数会增加数据丢失风险,需权衡。
网络延迟与带宽瓶颈
主从之间的网络延迟会影响 IO 线程拉取 binlog 的速度,但通常网络延迟对整体延迟影响较小,除非带宽不足。
解决方案:
- 使用专线或内网连接,避免公网。
- 检查网络带宽是否充足,如果 binlog 增长量大,考虑压缩传输。
进阶:半同步复制与组复制
除了优化从库执行能力,还可以通过改变复制模式来降低延迟的影响。半同步复制(Semisynchronous Replication)要求主库在提交事务时,至少等待一个从库确认收到 binlog,这样可以确保主库故障时不会丢失数据,但会增加主库的提交延迟。组复制(Group Replication)则提供了更高级的容错和一致性,但配置复杂。
对于延迟敏感的业务,可以考虑使用半同步复制,但需注意它可能增加主库的响应时间。如果业务对一致性要求高,可以评估组复制。
常见误区
- 误区:Seconds_Behind_Master 为 0 就代表没有延迟。实际上,如果主库长时间没有写入,该值可能为 0,但一旦有写入,延迟会立刻显现。
- 误区:只调大 slave_parallel_workers 就能解决所有延迟。并行复制需要事务之间没有冲突,如果业务中大量操作同一行,并行复制效果有限。
- 误区:延迟是网络问题,忽略从库性能。实际上,大部分延迟是由于从库执行慢,而非网络。
监控与告警
为了及时发现延迟,应建立监控机制。可以使用 Prometheus + Grafana 监控 MySQL 的复制状态,或使用现有的监控工具。设置合理的告警阈值,例如延迟超过 10 秒即告警。
参考资料
延伸阅读
