MySQL 主从延迟:从现象到根治

读写分离上线后最常见的线上问题:用户刚提交的数据,刷新页面就没了——主从延迟。这篇文章从延迟的成因讲起,到监控、优化、业务兜底,一套完整方案。

一、延迟从哪来

写 延 常 入 迟 见 主 根 1 2 3 4 库 = 因 . . . . : → 传 从 主 网 从 输 库 库 络 库 生 延 重 写 延 硬 成 迟 放 入 迟 件 慢 高 ( 弱 b + ( 峰 跨 ( i 大 ( 机 磁 n 重 事 b 房 盘 l 放 务 i ) 慢 o 延 、 n 、 g 迟 无 l 单 索 o 核 → 引 g 、 S 传 并 堆 Q 输 行 积 L 到 度 , 从 低 从 线 库 ) 库 程 跟 ) → 不 上 从 ) 库 S Q L 线 程 重 放 → 才 可 见

二、监控:看不到就管不了

1
2
3
4
5
6
7
-- 从库执行,看延迟秒数
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master:从库落后主库的秒数(关键指标)

-- 更精确:对比主从位点
SHOW MASTER STATUS;   -- 主库 File+Position
SHOW SLAVE STATUS;    -- 从库 Read_Master_Log_Pos

注意:Seconds_Behind_Master 有局限(从库空闲时可能显示 0,实际位点差很大)。生产用"位点差"监控(binlog 文件号 + 位置)。

告 警 阈 值 : 延 迟 > 3 s 告 警 , > 3 0 s 严 重 ( 看 业 务 容 忍 度 )

三、优化:降延迟三板斧

1. 从库并行重放

1
2
3
# MySQL 5.7+:并行复制(按库/按事务组)
slave_parallel_workers = 8
slave_parallel_type = LOGICAL_CLOCK   # 事务组并行(推荐)

原理:同一事务组内无冲突的事务并行重放,延迟可降 80%+。

2. 消灭大事务

大 优 事 化 务 1 : 批 避 大 0 量 免 表 = 操 长 万 作 事 D 重 行 拆 务 D 放 的 批 ( L 慢 ( 锁 U 每 用 + P 批 + 工 D 具 长 A 1 b ( 锁 T 0 i p E 0 n t + 0 l - → o o b 行 g s i 从 ) c n 库 累 ) l 要 积 或 o 重 ) 分 g 放 阶 很 段 巨 久 大

3. 索引对齐

从 ( → 库 有 重 人 从 放 给 库 慢 从 结 常 库 构 见 " 必 原 瘦 须 因 身 和 : " 主 从 删 库 库 索 一 缺 引 致 少 ( 主 → 读 库 写 有 重 分 的 放 离 索 全 引 表 ≠ 扫 ) 结 构 分 离 )

四、业务兜底:读不到就"读主"

延迟优化不到 0,业务要有兜底:

方案 1:关键读走主库

1
2
3
4
5
// 强一致场景(刚提交的数据必须立刻读到)走主库
func GetOrderAfterWrite(orderId string) *Order {
    // 写后立即读 → 主库(强一致)
    return queryMaster("SELECT * FROM orders WHERE id = ?", orderId)
}

原则:“写后读"场景(订单详情、评论发布、资料修改)走主库,其他读走从库。

方案 2:延迟可接受标记

写 读 → 操 操 作 作 触 返 对 发 回 比 " 时 : 稍 带 如 后 上 果 重 " 数 试 写 据 " 入 时 或 时 间 " 间 读 " > 主 库 当 " 前 时 间 - 延 迟 容 忍 ( 如 2 s )

方案 3:缓存先写

写 缓 库 存 里 + 有 写 = 缓 存 读 ( 到 同 新 事 数 务 据 / ; 同 缓 秒 存 ) 没 → 有 读 → 优 先 读 缓 从 存 库 ( 可 能 旧 )

五、踩坑记录

  1. 从库删索引"优化”:重放变全表扫,延迟暴涨 → 从库结构必须和主库一致
  2. 监控只看 Seconds_Behind_Master:从库空闲时虚报 0 → 用位点差 + 心跳表双监控
  3. 延迟时把流量切到从库:延迟 30s 还在从库读 → 业务直接"丢数据" → 延迟超过阈值切主库读
  4. 半同步的坑:半同步只保证"主库确认了从库收到 binlog",不保证"从库重放完"——半同步 ≠ 无延迟

六、什么时候用半同步

异 半 全 实 步 同 同 践 复 步 步 : 制 : : 同 : 主 所 机 主 库 有 房 库 等 从 半 不 一 库 同 等 个 确 步 从 从 认 库 库 ( + 确 确 数 认 认 据 跨 ( 收 最 机 性 到 安 房 能 全 异 好 b , 步 , i 性 ( 丢 n 能 灾 数 l 最 备 据 o 差 ) 风 g ) 险 ( 窗 降 口 低 大 丢 ) 数 据 窗 口 , 但 延 迟 + )

总结

主从延迟的核心认知:

  1. 延迟的根源:重放慢(大事务/缺索引)> 传输慢
  2. 监控用位点差:Seconds_Behind_Master 会虚报
  3. 优化三板斧:并行复制、拆大事务、索引对齐
  4. 业务兜底:写后读走主库、延迟阈值切换

主从延迟不可能为 0,但可以"业务感知不到":优化把延迟降到秒内,兜底把延迟关进笼子——读写分离才能稳定上线。