Java 小白必看:MySQL 主从延迟是什么?怎么排查?怎么彻底解决?
一、先搞懂什么是 MySQL 主从延迟咱们做 Java 开发很多时候会用「主从数据库」主库专门负责写数据比如用户下单、注册把数据存进去从库专门负责读数据比如用户查订单、查个人信息从这里读主库写完数据会通过网络同步给从库这个同步需要一点时间主从延迟就是主库已经写完数据了从库还没同步完导致你去从库查的时候查不到刚写的数据业务就出问题了。举个大白话例子你在淘宝下单主库已经记录了订单但从库还没收到这个数据你刷新页面就会显示「订单不存在」这就是主从延迟搞的鬼。二、小白也能做的排查步骤一步步跟着来步骤 1先确认是不是真的有主从延迟别上来就瞎改配置先确认问题是不是真的存在。打开你的数据库工具比如 Navicat、DBeaver或者服务器的命令行先在主库执行下面这条 SQL看主库最新的日志位置sqlSHOW MASTER STATUS\G再在从库执行下面这条 SQL看同步状态sqlSHOW SLAVE STATUS\G重点看这两个值Seconds_Behind_Master这个数字就是从库比主库慢了多少秒只要大于 0就是有延迟Exec_Master_Log_Pos从库已经执行到的日志位置和主库的Position差得越多延迟越严重小白提示如果这个数字是 0那大概率不是主从延迟的问题别再浪费时间啦。步骤 2先查自己的 Java 代码90% 的问题都出在这很多时候不是数据库的问题是咱们写代码的习惯不好把主从搞延迟了坑 1一次性插入 / 更新太多数据大事务小白最容易犯的错比如要给 10 万用户发优惠券直接把 10 万条数据一次性塞进数据库主库瞬间生成一大堆日志从库根本追不上❌ 错误代码千万别这么写java运行// 错误10万条数据一次性插入主库压力爆炸从库直接跟不上 Transactional public void batchInsertWrong(ListCoupon couponList) { couponMapper.batchInsert(couponList); }✅ 正确代码分批次给从库喘气的时间java运行// 正确每1000条数据一批次慢慢插主库压力小从库能跟上 Transactional(rollbackFor Exception.class) public void batchInsertRight(ListCoupon couponList) { // 每批1000条根据自己业务调整别太大就行 int batchSize 1000; for (int i 0; i couponList.size(); i batchSize) { int end Math.min(i batchSize, couponList.size()); couponMapper.batchInsert(couponList.subList(i, end)); } }大白话解释就像你搬 100 箱货一次性扛 100 箱肯定累瘫分 10 次每次扛 10 箱就轻松多了数据库也是一个道理。坑 2主库写完立刻去从库查很多小白写代码用户下单主库插入订单然后马上切到从库查订单状态这时候从库还没同步完肯定查不到✅ 解决方案两种小白选第一种就行核心业务订单、支付、用户信息强制走主库查别用从库直接查主库绝对不会出问题非核心业务比如统计、日志加个短暂的等待或者用缓存兜底举个 Spring Boot 的例子用 Sharding-JDBC 读写分离的同学直接用java运行// 加了Master注解强制走主库查询彻底解决延迟问题 Master public Order getOrderById(Long orderId) { return orderMapper.selectById(orderId); }步骤 3数据库层面的简单优化小白也能操作如果代码改完还是有延迟就给数据库做几个简单的优化立竿见影。优化 1给从库开「多线程同步」MySQL 5.7 直接用MySQL 老版本5.6 及以前从库只有一个线程同步数据主库并发写的时候从库肯定追不上MySQL 5.7 以后直接开多线程同步速度直接起飞。在从库执行下面的 SQL 就行sql-- 先停掉从库同步 STOP SLAVE; -- 开启基于逻辑时钟的多线程同步 SET GLOBAL slave_parallel_type LOGICAL_CLOCK; -- 设置同步线程数一般设4-8个根据服务器CPU核心数来 SET GLOBAL slave_parallel_workers 8; -- 重启从库同步 START SLAVE;小白提示执行完再用SHOW SLAVE STATUS\G看一下slave_parallel_workers变成 8 就成功了。优化 2检查从库的硬件和网络硬件从库的 CPU、磁盘别太差尤其是磁盘一定要用 SSD机械硬盘同步大日志会直接卡死网络主库和从库一定要放在同一个机房别一个在上海一个在广州网络延迟直接把同步搞崩小白排查命令服务器上执行bash运行# 看服务器CPU、内存占用有没有被打满 top -c # 看磁盘IO%util接近100%就是磁盘卡了 iostat -x 1 # 测主库到从库的网络延迟ping值超过10ms就有问题 ping 从库IP -c 100三、小白怎么预防主从延迟避坑指南永远别写大事务批量操作一定要分批次别一次性搞几十万条数据核心业务别用从库订单、支付、用户信息这些关键数据直接查主库别赌从库同步快给从库开多线程MySQL 5.7 直接开零成本提升同步速度加监控告警给主从延迟加个监控超过 5 秒就发消息提醒你别等用户投诉了才发现DDL 操作改表结构别在高峰期做改表会锁表从库同步会直接卡住一定要半夜没人的时候做四、小白常见问题解答Q1Seconds_Behind_Master是 0为什么还是查不到数据A这个数字是相对时间有一点点误差。如果是核心业务直接强制走主库查绝对不会出问题别纠结这个数字。Q2延迟偶尔出现不是一直有怎么办A大概率是你写了定时任务半夜批量更新数据导致瞬时延迟。把定时任务的批量操作改成分批次就解决了。Q3我是小白不想搞这么复杂有没有最简单的办法A有核心业务直接查主库非核心业务用 Redis 缓存兜底99% 的问题都能解决不用改数据库配置不用排查小白直接用。