文章总结: 本文系统梳理MySQL主从延迟的常见原因与诊断方案,强调需先区分I/O延迟与SQL应用延迟,避免盲目操作。核心建议包括确认版本与复制拓扑、使用GTID和心跳表监控端到端延迟、检查长事务与锁等待阻塞、分析从库资源瓶颈。文档提供了具体SQL查询和脚本示例,指导从网络、线程、锁、资源等多维度定位问题,并给出优化源端事务、调整并行复制等可操作建议。 综合评分: 87 文章分类: 解决方案,技术标准,安全运营
MySQL 主从延迟:常见原因与处理方案
点击关注👉 点击关注👉
马哥Linux运维
2026年7月18日 18:00 广东
在小说阅读器读本章
去阅读
MySQL 主从延迟:常见原因与处理方案
MySQL 主从延迟不是一个单一故障。它可能来自源库突然产生大事务、复制网络抖动、从库磁盘写入变慢、SQL 线程被锁、单线程回放能力不足、并行复制配置不合适,或者从库同时承担了过多查询。处理时最重要的是先判断延迟发生在“拉取 binlog”还是“应用 relay log”,再决定是优化源端事务、恢复网络、解除锁等待、提升从库能力还是调整复制并行度。
本文以 MySQL 8.0、GTID、异步复制为主。<源库地址>、<复制通道名>、<业务库名>、<表名>、<监控账号> 为占位符,必须替换成实际值。MySQL 8.0.22 起推荐 SOURCE/REPLICA 术语和命令,较早版本常见 MASTER/SLAVE 写法;执行前必须用 SELECT VERSION() 和 HELP 命令确认。
一、先确认版本、角色与复制拓扑
不要登录后直接执行 START REPLICA。先识别当前实例、只读状态、GTID 和通道数量,防止在源库或错误通道上操作。
sql
SELECT VERSION() AS mysql_version,
@@hostname AS host,
@@port AS port,
@@server_uuid AS server_uuid,
@@server_id AS server_id,
@@read_only AS read_only,
@@super_read_only AS super_read_only,
@@gtid_mode AS gtid_mode;
read_only 与 super_read_only 只是角色证据之一,不能单独证明实例一定是从库。代理层、双主拓扑和故障切换残留都可能改变角色判断。
列出所有复制连接和通道。多源复制必须按 channel 分析,不能只看默认通道。
sql
SELECT CHANNEL_NAME,
SERVICE_STATE,
SOURCE_UUID,
SOURCE_SERVER_ID,
RECEIVED_TRANSACTION_SET,
LAST_ERROR_NUMBER,
LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status
ORDER BY CHANNEL_NAME;
二、读取复制状态,但不要迷信单一字段
MySQL 8.0.22 及以上使用 SHOW REPLICA STATUS;旧版本使用 SHOW SLAVE STATUS。\G 只是 mysql 客户端纵向显示结束符,不应通过某些不兼容驱动发送。
sql
SHOW REPLICA STATUSG
优先检查 Replica_IO_Running、Replica_SQL_Running、Source_Log_File、Read_Source_Log_Pos、Relay_Source_Log_File、Exec_Source_Log_Pos、Relay_Log_Space、Last_IO_Error、Last_SQL_Error 和 Seconds_Behind_Source。
Seconds_Behind_Source 不是可靠的端到端业务延迟:线程停止时可能为 NULL,长事务提交前可能长时间不变,时钟异常和多线程应用也会影响解释。必须与 GTID、线程状态、心跳和 relay log 积压一起判断。
sql
SELECT CHANNEL_NAME,
THREAD_ID,
SERVICE_STATE,
LAST_ERROR_NUMBER,
LAST_ERROR_MESSAGE,
LAST_ERROR_TIMESTAMP
FROM performance_schema.replication_applier_status_by_coordinator;
查看 worker 能判断是否某个并行复制线程报错或长时间处理事务。
sql
SELECT CHANNEL_NAME,
WORKER_ID,
THREAD_ID,
SERVICE_STATE,
LAST_APPLIED_TRANSACTION,
LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
LAST_ERROR_NUMBER,
LAST_ERROR_MESSAGE
FROM performance_schema.replication_applier_status_by_worker
ORDER BY CHANNEL_NAME, WORKER_ID;
三、区分 I/O 延迟与 SQL 应用延迟
I/O 线程负责从源库接收 binlog 并写 relay log;SQL 协调器和 worker 负责应用。Replica_IO_Running 不是 Yes 时,先处理连接、账号、TLS、DNS、源端 binlog 和网络。I/O 正常但 Relay_Log_Space 持续增长,则重点检查 SQL 应用能力、锁和大事务。
sql
SELECT CHANNEL_NAME,
SERVICE_STATE,
LAST_PROCESSED_TRANSACTION,
LAST_PROCESSED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
PROCESSING_TRANSACTION,
PROCESSING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP
FROM performance_schema.replication_applier_status_by_coordinator;
检查复制连接最近错误。错误文本是定位认证、TLS、连接超时和 binlog 缺失的重要证据。
sql
SELECT CHANNEL_NAME,
SOURCE_UUID,
SERVICE_STATE,
LAST_ERROR_NUMBER,
LAST_ERROR_MESSAGE,
LAST_ERROR_TIMESTAMP
FROM performance_schema.replication_connection_status;
从从库主机验证到源库的 DNS、路由和 TCP 端口,只证明网络连通,不证明复制账号或协议成功。
bash
#!/usr/bin/env bash
set -euo pipefail
SOURCE_HOST="<源库地址>"
SOURCE_PORT="<源库端口>"
getent ahosts "$SOURCE_HOST"
ip route get "$SOURCE_HOST"
nc -vz -w 3 "$SOURCE_HOST" "$SOURCE_PORT"
四、建立独立的业务延迟心跳
最清楚的端到端延迟可以由源库周期性写入 UTC 时间,从库只读查询同一行。心跳表必须位于正常复制过滤范围内,不要使用从库本地表代替。
sql
CREATE DATABASE IF NOT EXISTS replication_monitor;
CREATE TABLE IF NOT EXISTS replication_monitor.heartbeat (
id TINYINT NOT NULL PRIMARY KEY,
source_ts TIMESTAMP(6) NOT NULL,
source_uuid CHAR(36) NOT NULL
) ENGINE=InnoDB;
建表属于 DDL,会写 binlog并复制到从库;执行前确认权限、命名规范和复制过滤。更新操作由源库上的受控调度器或外部任务执行。
sql
INSERT INTO replication_monitor.heartbeat (id, source_ts, source_uuid)
VALUES (1, UTC_TIMESTAMP(6), @@server_uuid)
ON DUPLICATE KEY UPDATE
source_ts = VALUES(source_ts),
source_uuid = VALUES(source_uuid);
从库查询当前 UTC 时间与源端时间差。若源从时钟没有同步,结果会失真,因此必须同时监控 NTP/Chrony。
sql
SELECT source_uuid,
source_ts,
UTC_TIMESTAMP(6) AS replica_now,
TIMESTAMPDIFF(MICROSECOND, source_ts, UTC_TIMESTAMP(6)) / 1000000 AS lag_seconds
FROM replication_monitor.heartbeat
WHERE id = 1;
五、检查是否被长事务拖住
复制按事务提交边界推进。源库一个持续数分钟、修改大量行的事务,只有提交后才进入完整应用阶段;从库应用该事务时可能只有部分 worker 忙碌。
源库检查长事务及其持续时间。
sql
SELECT trx_id,
trx_mysql_thread_id,
trx_started,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS age_seconds,
trx_rows_modified,
trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;
从库检查复制 worker 当前语句。performance_schema 中 SQL 文本可能因采集配置或语句结束而为空。
sql
SELECT t.PROCESSLIST_ID,
t.NAME,
t.PROCESSLIST_STATE,
es.EVENT_NAME,
es.SQL_TEXT,
es.TIMER_WAIT
FROM performance_schema.threads AS t
LEFT JOIN performance_schema.events_statements_current AS es
ON es.THREAD_ID = t.THREAD_ID
WHERE t.NAME LIKE 'thread/sql/replica%';
如果大事务来源是批量更新、一次性删除或无边界数据修复,长期方案应由应用拆分事务并在每批之间限速。直接杀源库事务会回滚并产生额外 I/O,属于高风险动作,必须评估业务一致性和回滚成本。
六、判断复制是否被锁等待阻塞
从库查询、备份、DDL 或运维语句可能持有锁,使复制 worker 等待。先查当前锁等待关系,而不是重启复制线程。
sql
SELECT waiting_pid,
waiting_query,
blocking_pid,
blocking_query,
locked_table,
locked_index,
wait_age
FROM sys.innodb_lock_waits
ORDER BY wait_age DESC;
再查看元数据锁。长时间打开的事务即使没有执行语句,也可能阻塞 DDL 或复制应用。
sql
SELECT ml.OBJECT_SCHEMA,
ml.OBJECT_NAME,
ml.LOCK_TYPE,
ml.LOCK_STATUS,
t.PROCESSLIST_ID,
t.PROCESSLIST_USER,
t.PROCESSLIST_TIME,
t.PROCESSLIST_INFO
FROM performance_schema.metadata_locks AS ml
JOIN performance_schema.threads AS t
ON ml.OWNER_THREAD_ID = t.THREAD_ID
WHERE ml.LOCK_STATUS IN ('PENDING', 'GRANTED')
ORDER BY ml.OBJECT_SCHEMA, ml.OBJECT_NAME;
终止阻塞会中断会话并可能回滚大事务。执行 KILL 前必须确认会话归属、事务大小、业务影响和应用重试行为;优先让业务方正常提交或回滚。
七、检查从库资源瓶颈
复制应用慢常见于磁盘 fsync 延迟、CPU 饱和、内存压力或从库查询竞争。只看 CPU 总利用率不够,需要同时观察 I/O 等待、磁盘延迟和 mysqld 线程。
bash
vmstat 1 10
iostat -xz 1 10
pidstat -p "$(pidof mysqld)" -rud 1 10
free -h
iostat 的 await、aqu-sz、%util 要结合磁盘类型和历史基线解释;云盘还可能受 IOPS、吞吐或突发额度限制。一次高 %util 不足以证明根因,必须与延迟增长时间对齐。
查看 MySQL 内部 InnoDB 写入、刷盘和脏页趋势。
sql
SHOW GLOBAL STATUS
WHERE Variable_name IN (
'Innodb_buffer_pool_pages_dirty',
'Innodb_data_fsyncs',
'Innodb_data_writes',
'Innodb_os_log_pending_fsyncs',
'Innodb_os_log_pending_writes',
'Threads_running'
);
若从库承担报表查询,还要检查高耗时 SQL 是否与复制争用 CPU、Buffer Pool 和磁盘。
sql
SELECT DIGEST_TEXT,
COUNT_STAR,
ROUND(SUM_TIMER_WAIT / 1000000000000, 2) AS total_seconds,
ROUND(AVG_TIMER_WAIT / 1000000000, 2) AS avg_ms,
SUM_ROWS_EXAMINED,
SUM_ROWS_SENT
FROM performance_schema.events_statements_summary_by_digest
WHERE SCHEMA_NAME = '<业务库名>'
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;
八、检查缺失索引和低效回放
同一条 UPDATE 在源库可能命中缓存,在从库因统计信息、缓存或索引不一致而更慢。先比对表定义和索引,再使用 EXPLAIN;不要直接用 EXPLAIN ANALYZE 执行可能修改或消耗大量资源的语句。
sql
SHOW CREATE TABLE <业务库名>.<表名>G
SHOW INDEX FROM <业务库名>.<表名>;
EXPLAIN FORMAT=TREE
SELECT <字段列表>
FROM <业务库名>.<表名>
WHERE <过滤条件>;
增加索引会消耗 CPU、I/O、临时空间并扩大复制日志。MySQL 8.0 对部分二级索引支持 INPLACE/LOCK=NONE,但并非所有表结构和操作都支持;应先在副本或测试环境验证。
sql
ALTER TABLE <业务库名>.<表名>
ADD INDEX <索引名> (<列名>)
ALGORITHM=INPLACE,
LOCK=NONE;
如果命令提示算法或锁级别不支持,不要移除限制强行执行。应重新评估维护窗口、在线 DDL 工具和复制拓扑。
九、检查并行复制配置
并行 worker 可提高不同事务的应用吞吐,但不能让单个巨大事务自动拆成多个独立事务。先查看当前配置和运行中的 worker 数量。
sql
SHOW VARIABLES
WHERE Variable_name IN (
'replica_parallel_workers',
'replica_parallel_type',
'replica_preserve_commit_order',
'binlog_transaction_dependency_tracking'
);
参数可在线修改的范围随版本变化。MySQL 8.0 某些版本要求停止 SQL 线程后修改 replica_parallel_workers;执行前用 SET 语法帮助和官方版本说明确认。以下流程会短暂停止指定通道的应用,期间延迟继续增长,属于生产变更。
sql
STOP REPLICA SQL_THREAD FOR CHANNEL '<复制通道名>';
SET GLOBAL replica_parallel_workers = 8;
START REPLICA SQL_THREAD FOR CHANNEL '<复制通道名>';
SHOW REPLICA STATUS FOR CHANNEL '<复制通道名>'G
worker 数量不是越多越好。过多 worker 会增加锁竞争、内存和调度开销;应以 relay log 消化速度、CPU、磁盘、冲突和业务查询影响评估。
十、核对 binlog 与 relay log
源库查看 binlog 列表和当前文件,确认复制请求的日志仍存在。不要为了释放空间手工删除正在被副本使用的 binlog。
sql
SHOW BINARY LOGS;
SHOW MASTER STATUS;
MySQL 新版本也提供 SHOW BINARY LOG STATUS;实际语法按版本确认。使用 mysqlbinlog 离线检查特定文件时,应在受控副本上操作,binlog 可能包含敏感数据。
bash
mysqlbinlog --base64-output=DECODE-ROWS -vv --start-datetime="<开始时间>" --stop-datetime="<结束时间>" <binlog文件> | less
Relay_Log_Space 持续增长表示接收速度高于应用速度;它本身不能说明具体是锁、磁盘、事务结构还是 worker 配置,需要回到前述证据。
十一、谨慎处理复制错误
Last_SQL_Error 非空时,先判断是数据不一致、DDL 顺序、重复键、缺行还是权限/引擎问题。不要把 SQL_SLAVE_SKIP_COUNTER 或跳过 GTID 当作通用修复;跳过事务会制造或扩大数据不一致。
sql
SELECT CHANNEL_NAME,
LAST_ERROR_NUMBER,
LAST_ERROR_MESSAGE,
LAST_ERROR_TIMESTAMP
FROM performance_schema.replication_applier_status_by_worker
WHERE LAST_ERROR_NUMBER <> 0;
处理前至少保存 SHOW REPLICA STATUS、错误事务 GTID、相关表校验、源从表结构和备份状态。若需要重建副本,应从一致性备份或克隆重新初始化,而不是不断跳过错误。
暂停整个通道会停止拉取和应用,可能增加源端 binlog 保留压力;只有在阻止错误继续扩大时才执行,并准备明确恢复命令。
sql
STOP REPLICA FOR CHANNEL '<复制通道名>';
SHOW REPLICA STATUS FOR CHANNEL '<复制通道名>'G
START REPLICA FOR CHANNEL '<复制通道名>';
十二、验证延迟正在收敛
修复后不要只看线程变为 Yes。应连续观察心跳延迟、Relay_Log_Space、已执行 GTID、worker 状态和业务读一致性,确认积压真正被消化。
sql
SELECT UTC_TIMESTAMP(6) AS observed_at,
TIMESTAMPDIFF(MICROSECOND, source_ts, UTC_TIMESTAMP(6)) / 1000000 AS lag_seconds
FROM replication_monitor.heartbeat
WHERE id = 1;
SHOW REPLICA STATUS FOR CHANNEL '<复制通道名>'G
若延迟下降速度低于源库新增事务速度,积压不会清空。此时应继续降低从库额外负载、优化慢事务或临时提升实例能力,而不是宣布恢复。
十三、监控与告警
应同时监控连接线程、应用线程、心跳延迟、relay log 空间、复制错误、磁盘延迟、CPU 和从库查询负载。Prometheus 指标名称以实际 exporter 暴露的指标为准,不同 mysqld_exporter 版本和采集器会不同。
下面的巡检脚本通过 mysql 客户端只读查询状态。密码不应写入脚本,应使用权限为 0600 的 option file 或密钥管理系统。
bash
#!/usr/bin/env bash
set -euo pipefail
MYSQL_CNF="<只读账号配置文件>"
CHANNEL="<复制通道名>"
mysql --defaults-extra-file="$MYSQL_CNF" --batch --raw <<SQL
SELECT VERSION(), @@hostname, @@read_only, @@super_read_only;
SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status;
SELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE, LAST_ERROR_NUMBER
FROM performance_schema.replication_applier_status_by_worker;
SELECT TIMESTAMPDIFF(MICROSECOND, source_ts, UTC_TIMESTAMP(6))/1000000
FROM replication_monitor.heartbeat WHERE id=1;
SHOW REPLICA STATUS FOR CHANNEL '$CHANNEL';
SQL
十四、处理路径总结
I/O 线程异常,先查网络、账号、TLS、源端 binlog 与连接错误;I/O 正常而 relay log 增长,查锁、大事务、索引、磁盘、CPU、从库查询和并行复制;复制报错则先保护证据和校验一致性;延迟恢复后仍要观察收敛速度和业务读结果。
可靠处理的标准不是 Seconds_Behind_Source 短暂归零,而是复制链路稳定、心跳延迟恢复、relay log 积压下降、没有 worker 错误、资源回到基线且数据一致性得到验证。
文末阅读福利
仅目前来说,无论是运维人转型提升,还是零基础想转行IT,最好的岗位就是云计算运维&SRE岗位。
为了帮助大家早日快速入门云计算运维领域,给大家整理了一套【最新运维资料】高级运维工程师必备技能资料包(文末一键免费领取),内容有多详实丰富看下图!
1.38张最全工程师技能图谱
2.面试大礼包
3.Linux书籍
内容比较多,就不一一展示了
以上所有资料获取请扫码:
识别上方二维码
备注:2026最新运维资料
100%免费领取
(是扫码领取,不是在公众号后台回复,别看错了哦)
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:马哥Linux运维 点击关注👉 点击关注👉《MySQL 主从延迟:常见原因与处理方案》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论