主从同步延迟踩坑

张开发
2026/4/9 12:42:14 15 分钟阅读

分享文章

主从同步延迟踩坑
主从同步延迟踩坑下单成功却看不到订单排查与解决全过程背景电商系统做了读写分离写操作走主库读操作走从库。上线后偶发一个奇怪的问题用户下单成功后立刻跳转订单详情页概率性出现订单不存在刷新一下又正常了。客服反馈频率大概是每天十几次集中在促销活动期间。问题定位第一反应是代码 bug查了半天逻辑没问题。后来在日志里发现一个规律报错的请求下单写入和查询详情的时间间隔都在 500ms 以内。这个时间间隔让人想到一个可能主从同步延迟。用户写入主库成功立刻去从库查从库还没同步到这条数据查不到返回不存在。确认主从延迟登录从库执行SHOWSLAVESTATUS\G关键字段Seconds_Behind_Master: 3Seconds_Behind_Master表示从库落后主库的秒数。正常情况应该是 0 或接近 0促销高峰期这个值飙到了 3-8 秒偶尔更高。用户下单后 500ms 内去查从库可能还差着好几秒当然查不到。主从延迟的产生原因MySQL 主从同步的流程主库写入 → binlog → 从库 IO 线程拉取 binlog → relay log → 从库 SQL 线程回放延迟产生在最后一步从库 SQL 线程单线程回放。主库可以并发写入但从库默认只有一个 SQL 线程串行回放 binlog高并发写入时从库根本跟不上主库的节奏延迟越积越大。其他常见原因从库服务器性能比主库差网络带宽不足binlog 传输慢从库有大查询占用资源影响回放速度解决方案方案一写后读强制走主库最简单推荐对于写完立刻读的场景强制这次读走主库绕过延迟问题// 下单成功后跳转详情页时强制读主库$orderDB::connection(mysql_master)-table(orders)-where(id,$orderId)-first();或者更优雅的做法在 Session 里打一个标记// 下单成功后Session::put(force_master_until,time()3);// 3秒内走主库// 读取时判断publicfunctiongetConnection():string{if(Session::get(force_master_until,0)time()){returnmysql_master;}returnmysql_slave;}优点改动小精准处理不影响其他读操作。缺点需要业务层感知主从有一定侵入性。方案二读主库等待从库同步写入主库后等从库同步完成再跳转-- 主库写入后获取当前 binlog 位置SHOWMASTERSTATUS;-- 返回File mysql-bin.000123, Position 456789-- 在从库执行等待同步到指定位置超时 5 秒SELECTMASTER_POS_WAIT(mysql-bin.000123,456789,5);-- 返回 0同步完成-- 返回 -1超时-- 返回 NULL复制未启动PHP 实现publicfunctionplaceOrder(array$data):int{// 主库写入$orderIdDB::connection(mysql_master)-table(orders)-insertGetId($data);// 获取主库当前位置$masterStatusDB::connection(mysql_master)-selectOne(SHOW MASTER STATUS);// 等待从库同步最多等 3 秒$resultDB::connection(mysql_slave)-selectOne(SELECT MASTER_POS_WAIT(?, ?, 3) as synced,[$masterStatus-File,$masterStatus-Position]);if($result-syncednull||$result-synced0){// 超时或复制异常降级走主库查询return$this-getOrderFromMaster($orderId);}return$orderId;}优点精确等待不浪费等待时间。缺点增加了下单接口的响应时间延迟高峰期用户体验变差。方案三开启并行复制从根源降低延迟MySQL 5.7 支持并行复制从库可以多线程回放 binlog大幅降低延迟# 从库 my.cnf 配置 [mysqld] slave_parallel_type LOGICAL_CLOCK # 基于逻辑时钟的并行 slave_parallel_workers 8 # 8 个并行线程 slave_preserve_commit_order 1 # 保证提交顺序配置后重启从库复制STOP SLAVE;STARTSLAVE;-- 验证并行线程是否生效SHOWPROCESSLIST;-- 应该能看到多个 system user 线程在执行开启后实测延迟从平均 3 秒降到 0.1 秒以内促销高峰期也基本维持在 1 秒以下。优点治本不需要业务层改动。缺点需要 MySQL 5.7且并行复制对 binlog 格式有要求需要 ROW 格式。最终落地方案三个方案组合使用开启并行复制把基准延迟降下来治本写后读走主库针对下单→查详情等关键链路做兜底治标监控Seconds_Behind_Master超过 5 秒触发告警及时发现异常-- 定时监控脚本SELECTVARIABLE_VALUEASseconds_behind_masterFROMperformance_schema.global_statusWHEREVARIABLE_NAMESeconds_Behind_Master;上线后订单不存在报错归零持续观察两周无复发。总结主从延迟问题排查步骤SHOW SLAVE STATUS确认Seconds_Behind_Master判断延迟原因写入量大、从库性能差、网络问题业务层关键读写操作强制走主库架构层开启并行复制降低基准延迟运维层建立延迟监控告警读写分离不是银弹引入的主从延迟问题必须配套处理否则会踩坑。

更多文章