MySQL 主从延迟别只答并行复制

主从延迟压不到零。并行复制治标不治本,超阈值就强制走主库,或者承认异步复制不适合你。Seconds_Behind_Master 也别全信。

面试官问的是延迟,考的是你能不能把手段挂回链路上

答不好这题,通常不是不知道优化手段,而是说不出这些手段作用在复制的哪一环。链路都讲不清,优化就只能靠背。

五个步骤得能顺口说出来:

sequenceDiagram participant Main as 主库 Master participant BLog as BinLog participant Dump as dump 线程 participant IO as 从库 IO 线程 participant Relay as RelayLog participant SQL as 从库 SQL 线程 Main->>BLog: 1 更新事件写入 BinLog IO->>Main: 2 从库发起连接 Main->>Dump: 3 主库创建 dump 线程 Dump->>IO: 4 推送 BinLog 内容到从库 IO->>Relay: 5 写入 RelayLog SQL->>Relay: 6 从 Exec_Master_Log_Pos 位点读取 SQL->>SQL: 7 回放到从库 DB

记住一点:第 4 到第 7 步之间,是从库自己在消化,延迟主要就长在这一段。你说的每一个优化手段,都得能指回这条链路的某一环。

延迟的两笔账,分开算

第一笔是网络。跨机房、跨地域的 RTT 从几毫秒到几十毫秒,物理距离决定的,能优化的只有带宽和机房规划。

第二笔是回放。主库 8 核并发写,从库默认只有一个 SQL 线程串行回放。主库写得越快,从库追得越吃力。

所以延迟的本质就一句话:主库的并发写入能力和从库的串行回放速度之间的差。所有优化,要么缩小这个差,要么绕开这个差。

flowchart TD A[发现主从延迟] --> B{延迟超过业务阈值吗} B -->|没超过| C[并行复制 + 拆大事务 + 从库 SSD] B -->|超过了| D{读请求能容忍旧数据吗} D -->|能| E[一主多从 分摊读压力] D -->|不能| F[强制路由主库读] F --> G[长期方案 半同步 或 MGR 或分布式数据库] C --> H[继续观测延迟水位] E --> H G --> H

第一层:能压的先压

大事务不拆,别的优化都是白费

一个大事务在 binlog 里就是一个巨大事件,从库 SQL 线程要一口气回放完,期间后面的事务全部排队。主库执行 3 秒,从库可能要卡 30 秒。

sql 复制代码
-- 反例 一条语句删 200 万行
DELETE FROM orders WHERE create_time < '2024-01-01';
sql 复制代码
-- 正解 每批 5000 行 循环提交
DELETE FROM orders WHERE create_time < '2024-01-01' LIMIT 5000;

大事务的坑不止延迟:主库 binlog 暴涨、从库 relay log 堆积、回放失败时重试代价极高。能拆就拆,这是性价比最高的手段。

并行复制:版本不一样,答案就不一样

视频重点提了这个,但版本差异必须讲清楚,否则面试官一追问就露馅。

ini 复制代码
# my.cnf on slave
slave_parallel_workers = 8
slave_parallel_type = LOGICAL_CLOCK
slave_preserve_commit_order = ON
  • 5.6 的 DATABASE 模式:按库并行,同一个库的事务还是串行。库少的业务基本没用。
  • 5.7 的 LOGICAL_CLOCK:基于主库组提交,同一组内提交的事务可以并行回放,这是质变。
  • 8.0 的 WRITESET:基于行级冲突检测,只要事务间没有写冲突就能并行,几乎榨干从库多核。

slave_preserve_commit_order=ON 别漏,它保证从库提交顺序和主库一致。关了确实更快,但可能读到中间状态。

换 SSD,最朴素的一招

机械盘换 SSD,随机写 IOPS 差一到两个数量级,回放速度直接翻倍。没有花活,但有效。

一主多从解决不了回放延迟

这里有个高频误区:一主多从解决的是"读请求压力",不是"回放延迟"。

每个从库都要完整回放同一份 binlog 流,加机器不会让单个从库追得更快。视频里说的"分摊从库压力",指的是把查询流量摊开,不是让延迟变小。这个区别能主动说出来,直接加分。

第二层:延迟消不掉,就在读路径兜底

压不到零,那就接受它,然后在读路径上兜底。

强制走主库

写后立刻读的场景------下单后查订单、支付后查余额------直接路由到主库。中间件规则或者 SQL hint 都行。代价是主库读压力上升,所以只对强一致要求的那几条链路开。

轮询等待从库追平

视频里提到的做法:查 Seconds_Behind_Master,大于阈值就 sleep,再查。

sql 复制代码
SHOW SLAVE STATUS\G
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- Seconds_Behind_Master: 3
-- Read_Master_Log_Pos: 1207
-- Exec_Master_Log_Pos: 4823
java 复制代码
// 等待从库延迟收敛,超时则降级走主库
public boolean waitForSlave(long timeoutMs, long thresholdSec) {
    long deadline = System.currentTimeMillis() + timeoutMs;
    while (System.currentTimeMillis() < deadline) {
        Long delay = querySecondsBehindMaster(); // 结果本地缓存 100ms,别每个请求都查
        if (delay != null && delay <= thresholdSec) {
            return true;
        }
        LockSupport.parkNanos(100_000_000L); // 100ms 重试
    }
    return false;
}

注意这段代码的代价:探针本身也有开销,QPS 上万时别每个读请求查一次,缓存一下。

Seconds_Behind_Master 到底能不能信

不能。它算的是从库 SQL 线程当前回放事件的 timestamp 与从库当前时间的差,有三个坑:

  1. IO 线程积压但 SQL 线程刚好回放到新事件时,它可能显示 0,实际 relay log 堆了一大堆。
  2. 主库长时间无写入,SQL 线程空转,它显示 0 或 NULL,不代表数据同步完成。
  3. 想精确判断,看 Read_Master_Log_Pos - Exec_Master_Log_Pos 的位点差,或者 performance_schema.replication_applier_status_by_worker

它是一个粗略水位线,不是延迟的精确度量。 面试里主动说出这点,比多背两个参数管用。

第三层:要强一致,就别用异步复制

这是视频最后给出的态度,也最容易被忽略:主从复制的场景无法避免同步延迟,如果一定要强一致,就该考虑其他技术方案。

方案 一致性 代价
异步复制 最终一致 延迟不可避免
半同步复制 至少一个从库收到 binlog 每次提交多一个 RTT,TPS 下降
MGR 多数派确认 部署复杂,网络要求高
分布式数据库 线性一致 换底座

半同步只保证"从库收到了 binlog",不保证已经回放完,写后读仍然可能读到旧数据。

面试追问链

Q:并行复制会不会导致主从数据不一致? A:开了 slave_preserve_commit_order 就不会。并行只影响回放阶段的调度,提交顺序仍与主库一致。

Q:slave_parallel_workers 开多大? A:一般不超过从库 CPU 核数,8 核从库开 8 到 16 比较常见。开太大反而因锁竞争变慢,得实测。

Q:半同步能彻底解决延迟吗? A:不能。它解决的是"数据不丢",不是"延迟为零",只保证一个从库收到 binlog。

Q:一主多从能解决回放延迟吗? A:不能,只能分摊读流量。每个从库都独立回放全量 binlog。

写在最后

异步复制下的主从延迟不是 bug,是设计。你能做的是把它压到业务能忍的量级,压不下去就换方案------而不是继续加从库。

真正难的不是记住这些手段,而是判断"延迟多少算超标"------1 秒?200 毫秒?这个阈值得由业务定,不是由 DBA 定。

你们线上怎么处理写后读?强制打主库,还是等延迟水位?评论区聊聊。

有用的话点个赞。

相关推荐
这个DBA有点耶1 小时前
当Agent从“写SQL”变成“执行SQL”:数据库安全模型需要重新设计
数据库·aigc·dba
SamDeepThinking1 小时前
Java 17内存屏障:为什么需要,怎么用
java·后端·面试
CC数分1 小时前
2026年金融数据分析岗位需要哪些工具?2027届秋招备考指南
面试·数据分析
狼与自由2 小时前
MCP协议理解
人工智能·架构
qq_401700412 小时前
Qt QUrl 详解与代码示例
开发语言·数据库·qt
程序员阿鹏2 小时前
如何实现MySQL分库分表?
数据结构·数据库·sql·mysql·缓存
风哥2号3 小时前
数据库教程FGMT33‑MySQL主从复制项目实施与维护06(MySQL8.4/9.7 MGR组复制)
数据库·mysql
liangsheng_g3 小时前
Spring事务传播行为分派与挂起恢复源码实战
数据库·sql·spring
蓝速科技3 小时前
信创终端 POC 测试实战与选型避坑指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理