"主从延迟 10 分钟"不是一个根因,而是一条结果。它可能由主库突发大事务、从库单线程回放、磁盘 fsync 抖动、只读报表挤占 I/O、网络重传、复制错误重试,或级联复制拓扑中上游本身已经落后造成。直接把告警阈值调大、重启从库、跳过事务,都会改变现场证据,甚至造成数据不一致。
本文使用 MySQL 8.0 的 SOURCE/REPLICA 术语。MySQL 5.7 仍可能显示 MASTER/SLAVE 字段,例如 SHOW SLAVE STATUS\G;先以实际版本为准。本文只讨论 binary log 异步/半同步复制,不混用 Group Replication 的状态变量。<源库主机>、<副本主机>、<复制用户>、<业务库>、<表名> 是占位符,执行前必须替换。
一、告警发生后先保留证据,不要立即"修复"
除非数据一致性或主库稳定性面临明确风险,先采集 source binlog 坐标、IO/SQL 线程状态、worker 执行情况、慢查询、磁盘延迟和网络状态。STOP REPLICA、重启 mysqld 或 SET GLOBAL sql_replica_skip_counter=1 都可能让后续排障失去关键证据。高质量处置先回答三个问题:数据是否还在复制、哪一段跟不上、延迟是在收敛还是扩大。
1. 确认实例版本和复制语法
SELECT VERSION() AS mysql_version,
@@version_comment AS version_comment,
@@server_uuid AS server_uuid,
@@server_id AS server_id;
版本确认决定后续使用 SHOW REPLICA STATUS 还是兼容命令。不要让自动化脚本假定两个命令都可用;不同小版本、云数据库和客户端显示的字段也可能不同。
2. 采集副本复制状态快照
SHOW REPLICA STATUS\G
保存真实输出并至少关注 Replica_IO_Running、Replica_SQL_Running、Seconds_Behind_Source、Source_Log_File、Read_Source_Log_Pos、Relay_Source_Log_File、Exec_Source_Log_Pos、Relay_Log_Space、Last_IO_Error 与 Last_SQL_Error。线程不是 Yes 时,首先是复制中断,而不是性能延迟。
3. 在 MySQL 5.7 环境使用兼容命令
SHOW SLAVE STATUS\G
此命令只适用于 5.7 或仍支持兼容语法的环境。字段含义和 8.0 新术语对应,但应以实际返回列名为准。不要混用不同版本的配置项,例如 5.7 的 slave_parallel_workers 和 8.0 的 replica_parallel_workers 需要分别确认。
SELECT CHANNEL_NAME, SERVICE_STATE,
LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status;
SELECT CHANNEL_NAME, SERVICE_STATE,
LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_applier_status;
多源复制会有多个 CHANNEL_NAME,不能默认只看空 channel。Performance Schema 的结构化结果更适合巡检和监控,但前提是该性能库已经启用且运行账户有读取权限。
5. 看并行 worker 是否被单个事务卡住
SELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE,
LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE,
LAST_APPLIED_TRANSACTION, APPLYING_TRANSACTION
FROM performance_schema.replication_applier_status_by_worker
ORDER BY CHANNEL_NAME, WORKER_ID;
多数 worker 空闲、少数 worker 长期处于 APPLYING_TRANSACTION,常见证据是大事务、热点行锁、DDL 或提交顺序等待。
已经设置了多个 worker 并不保证实际并行度高,事务依赖关系仍会限制回放。
6. 记录 source 的 binary log 基线配置
SHOW VARIABLES WHERE Variable_name IN (
'log_bin',
'binlog_format',
'gtid_mode',
'enforce_gtid_consistency',
'binlog_transaction_dependency_tracking',
'sync_binlog'
);
binlog_format=ROW 通常是生产复制的基础。记录原值是后续变更、回滚和跨版本判断的前提;不要只因为存在延迟就修改 sync_binlog 或一致性相关参数,那会改变故障场景下的数据持久性保证。
7. 用 GTID 判断真实追赶范围
SELECT @@GLOBAL.gtid_executed AS replica_gtid_executed,
@@GLOBAL.gtid_purged AS replica_gtid_purged;
在 source 和 replica 上同一轮采集。Seconds_Behind_Source 在 SQL 线程停止、并行回放、时钟偏差和长事务场景下并不总能准确代表新鲜度;GTID 集合更能证明已执行到哪里,但事务数量不等于字节量或实际耗时。
8. 在 source 计算副本尚未执行的 GTID
SELECT GTID_SUBTRACT(
@@GLOBAL.gtid_executed,
'<从副本采集的 replica_gtid_executed>'
) AS transactions_not_on_replica;
把占位符替换为本次副本快照的完整 GTID 集。空结果表示副本已追平;非空只说明积压存在,不能凭 GTID 字符串长度估算还要多久。对于多源复制必须按 channel/source 的事务来源分析。
9. 检查 source binlog 增长与当前写入位置
SHOW BINARY LOGS;
SHOW MASTER STATUS;
观察最近文件增长趋势并对照业务发布、批处理和 DDL 时间线。文件大小不能直接证明某个事务就是根因,仍需与慢日志、应用作业记录和 worker 状态对应。
10. 在副本查看 relay log 是否持续积压
SHOW GLOBAL STATUS WHERE Variable_name IN (
'Relay_log_space',
'Bytes_received',
'Bytes_sent',
'Threads_running',
'Threads_connected'
);
Relay_log_space 连续增长、连接线程正常而 applier 跟不上,指向回放侧瓶颈;不增长且 IO 线程停止,则优先排查网络、认证、source binlog 保留或连接错误。至少连续采样几次,单点值没有趋势意义。
11. 读取错误日志中的复制、InnoDB 和磁盘证据
sudo journalctl -u mysqld --since '<开始时间>' --until '<结束时间>' --no-pager | \
rg -i 'replica|slave|source|master|relay|innodb|error|disk|space'
适用于 systemd 管理的 Linux。若 log_error 指向独立文件,应读取实际路径。日志中出现 No space left on device、连接错误、relay log 读取错误、死锁或崩溃恢复信息,才是相应结论的证据;无关 warning 不能作为根因。
12. 检查数据、relay log 和临时目录空间
df -hT <mysql数据目录> <relay-log目录> <tmp目录>
df -i <mysql数据目录> <relay-log目录> <tmp目录>
除了容量比例还要看 inode。不要手工删除 relay log 来腾空间;MySQL 的复制元数据管理 relay log 生命周期,误删会破坏复制。空间不足时先按变更流程扩容、清理确认无依赖的文件或从备份/归档流程释放空间。
13. 连续观察存储延迟和队列深度
iostat -xmd 1 10
需要 sysstat。关注 MySQL 所在块设备的 await、r_await、w_await、aqu-sz 和 %util 趋势,并与延迟窗口和健康副本对照。没有适用于所有云盘和 RAID 的统一阈值,不能用单次高值断言 I/O 为根因。
14. 观察 CPU、内存换页与运行队列
vmstat 1 10
mpstat -P ALL 1 10
需要 sysstat。运行队列持续偏高、iowait 上升、持续 si/so 都可能解释 applier 变慢,但必须结合 mysqld 线程、容器限额和磁盘指标判断。备份、校验、ETL 和报表也会挤占 replica。
15. 检查 source 到 replica 的网络路径
ping -c 20 <源库主机>
ss -tnpi | rg ':3306\b'
ping 只验证 ICMP 可达,不证明 MySQL TCP 质量;ss 的 TCP 重传信息也受内核与权限影响。下结论应结合网络监控、丢包/重传、IO 线程错误和跨机房链路数据。
二、按链路把"慢"分成四类
复制至少包含 source 到 relay log 的拉取,以及 relay log 到 InnoDB 的回放。事务还可能在 fsync 或提交顺序等待中变慢;级联复制还会把上游延迟传递给下游。分类正确后,优化才不会变成对无关参数的盲调。
16. 结构化区分连接线程与 applier 线程失败
SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status
UNION ALL
SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_applier_status;
连接线程失败优先处理 TLS、用户权限、网络、source 可达性和 binlog 缺失;applier 失败优先处理 SQL 错误、数据差异、磁盘和 DDL 兼容。没有错误码和 GTID 之前,不应授权跳过事务。
17. 检查副本上的长事务与锁竞争
SELECT trx_id, trx_started, trx_state,
trx_mysql_thread_id, trx_rows_modified,
trx_rows_locked, trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;
副本本地报表或运维查询也可能持锁、阻碍 purge 或和 applier 的 DDL 竞争。trx_query 可能包含敏感内容;输出应按数据分级保存。不能仅因事务存在就 KILL,必须先确认业务 owner、回滚代价和锁影响。
18. 读取副本上累计等待最多的语句摘要
SELECT DIGEST_TEXT, COUNT_STAR,
ROUND(SUM_TIMER_WAIT / 1000000000000, 2) AS total_seconds,
ROUND(AVG_TIMER_WAIT / 1000000000000, 4) AS avg_seconds
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;
摘要表从实例启动或统计重置后累计,不等同于本次事故窗口。应保留快照并结合慢日志/APM 的时间范围判断。若报表查询长期占据 I/O,优先移出故障切换候选副本,而不是盲目增加并行 worker。
三、回放慢时的并行复制优化
IO 线程正常、relay log 持续增长、applier worker 跟不上时,才进入并行复制优化。目标是让独立事务并行应用,而不是无条件提高 worker 数。单个巨大事务、同一热点行的持续写入、全局 DDL 和严格提交顺序都可能让并行度收益很低。
19. 查看并行复制当前设置
SHOW VARIABLES WHERE Variable_name IN (
'replica_parallel_workers',
'replica_parallel_type',
'replica_preserve_commit_order',
'replica_checkpoint_group',
'replica_checkpoint_period'
);
默认值和上限随版本变化,应以真实实例为准。replica_parallel_workers=0 表示单线程应用;已有 worker 也可能闲置,必须用 worker 状态和 CPU/I/O 证明瓶颈确实可通过并行度改善。
20. 先在非关键副本小幅灰度提高 worker
SET GLOBAL replica_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL replica_parallel_workers = <worker数量>;
<worker数量> 应依据 CPU、存储、压测与当前负载确定,不要直接设为核数或很大的常数。具体参数何时对 applier 生效需以本版本文档和状态验证为准;先记录原值,观察延迟、worker、错误日志和 I/O 后再决定是否固化。
21. 受控重启 SQL/applier 线程加载设置
STOP REPLICA SQL_THREAD;
START REPLICA SQL_THREAD;
SHOW REPLICA STATUS\G
这是有影响操作:停止期间 applier 不推进,短时延迟会增加,IO 线程仍可能继续写 relay log。执行前确认 relay log 空间充足且不存在复制错误;多源复制必须对正确 channel 操作。完成后检查线程和 worker,而不是只看命令无报错。
22. 将已经验证的参数写入配置片段
[mysqld]
# 仅在压测和灰度验证后启用
replica_parallel_type=LOGICAL_CLOCK
replica_parallel_workers=<worker数量>
replica_preserve_commit_order=ON
配置文件位置因发行版而异,常见为 /etc/my.cnf 或 /etc/mysql/my.cnf。replica_preserve_commit_order=ON 有助于保持提交顺序,可能带来等待;读一致性和故障切换要求通常比微小吞吐更重要。
23. 在 source 检查并评估依赖跟踪模式
SHOW VARIABLES LIKE 'binlog_transaction_dependency_tracking';
SET GLOBAL binlog_transaction_dependency_tracking = 'WRITESET';
WRITESET 为后续 binlog 提供更细的事务依赖信息,可能提升支持条件下的并行回放。它是影响 source 的变更,需评估 CPU、版本兼容、所有副本特性和回滚计划。它不能把一条大事务拆开,也不能消除业务热点写冲突。
24. 读取 applier worker 的运行态来验证收益
SELECT WORKER_ID, SERVICE_STATE,
APPLYING_TRANSACTION,
LAST_APPLIED_TRANSACTION,
LAST_ERROR_NUMBER
FROM performance_schema.replication_applier_status_by_worker
ORDER BY WORKER_ID;
变更后应同时看到延迟收敛、多个 worker 出现有意义的工作、CPU/I/O 未饱和、无新错误。若 worker 仍绝大多数空闲,瓶颈可能是依赖关系或单一大事务,继续加 worker 没有意义。
四、大事务、DDL 与热点:参数无法替代写入治理
一条大事务通常作为整体记录和应用。即使 replica 有很多 worker,它也不能将同一个事务内部拆开;长时间的 ALTER TABLE、大批量 UPDATE/DELETE、大导入和没有节流的数据修复都可能让延迟迅速堆积。此时最有效的手段往往是拆分事务、控制并发、选择合适的在线 DDL 方式,并安排在可观察的窗口中执行。
25. 只读检查可疑时间窗口的 binlog 内容
mysqlbinlog --read-from-remote-source=BINLOG-DUMP-GTIDS \
--host=<源库主机> --port=3306 --user=<只读分析用户> \
--start-datetime='<开始时间>' --stop-datetime='<结束时间>' \
--base64-output=DECODE-ROWS --verbose \
<binlog文件名> > binlog-window.sql
该命令需要具备读取 binary log 的受控分析账户,具体权限随版本变化。输出可能含业务数据和敏感字段,必须保存在受控目录并按安全要求清理;先用 mysqlbinlog --help 确认本地客户端支持的 --read-from-remote-source 选项。
26. 检查当前仍在运行的长事务
SELECT trx_id, trx_started,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS age_seconds,
trx_rows_modified, trx_rows_locked, trx_query
FROM information_schema.innodb_trx
ORDER BY age_seconds DESC;
查询只能看到当前未提交事务;已经完成的大事务需从 binlog、慢日志和应用作业记录中查找。终止事务是高风险操作,必须先确认 thread id、业务 owner、回滚代价和持锁影响,不能为了让图表恢复就直接 KILL。
27. 以分批提交替代一次性批量更新的操作骨架
#!/usr/bin/env bash
set -euo pipefail
MYSQL_HOST="<源库主机>"
MYSQL_DB="<业务库>"
BATCH_SIZE=1000
while :; do
affected="$(mysql --host="${MYSQL_HOST}" --database="${MYSQL_DB}" \
--batch --skip-column-names -e "
UPDATE <表名>
SET <字段名> = <目标值>
WHERE <可重复筛选条件>
LIMIT ${BATCH_SIZE};
SELECT ROW_COUNT();")"
[[ "${affected}" == "0" ]] && break
sleep 1
done
这是操作骨架,不可直接执行。筛选条件必须幂等、可重复,且要确认 LIMIT 不会因无确定顺序而遗漏或反复处理。生产前先在预发布验证,设置限速、记录批次进度、监控复制延迟;延迟持续恶化时停止后续批次,而不是强制中断已在提交的事务。
28. 检查表大小、索引和 DDL 风险前置条件
SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE,
TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = '<业务库>'
AND TABLE_NAME = '<表名>';
SHOW CREATE TABLE <业务库>.<表名>;
TABLE_ROWS 对 InnoDB 是估算值,但足以提醒表规模与索引规模。真正执行 DDL 前还要评估 MySQL 版本、ALGORITHM/LOCK 能力、外键、触发器、应用写入模式和复制链路;不能因为有 INPLACE 或 INSTANT 关键字就假设所有变更零影响。
29. 显式请求 DDL 算法与锁级别,拒绝意外降级
ALTER TABLE <业务库>.<表名>
ADD INDEX <索引名> (<列名>),
ALGORITHM=INPLACE,
LOCK=NONE;
这是高风险 DDL 示例,只有在实际 MySQL 版本和表结构确认支持时才可执行。显式指定算法和锁级别的价值在于:不支持就报错,而不是静默回退到更重的表重建或写锁。执行前完成备份、容量评估、灰度和回滚预案;索引添加的回滚是 DROP INDEX,同样会产生资源影响。
30. 用慢日志检查 source 是否有异常写入模式
SHOW VARIABLES WHERE Variable_name IN (
'slow_query_log',
'long_query_time',
'log_queries_not_using_indexes',
'log_output'
);
慢日志不是事务大小的完整记录,但能帮助关联事故窗口中的慢 DML 和 DDL。修改慢日志参数会影响开销与日志量,需走变更流程;不要为了排障永久打开高开销审计而没有保留策略。
31. 只读汇总慢日志中最慢的语句模板
sudo mysqldumpslow -s t -t 20 <慢日志文件路径>
mysqldumpslow 适用于文本格式慢日志;若 log_output=TABLE 或使用外部日志系统,应选择对应查询方式。命令输出是汇总线索,不等价于证明某条语句导致复制延迟,仍需对照执行时间、锁、binlog 与 worker 状态。
五、复制拓扑优化:将故障切换、读流量、备份和分析隔离
单个副本同时承担实时只读、报表、备份、ETL、校验和多个下游复制,延迟几乎不可避免。拓扑设计首先要定义每台副本的角色:故障切换候选强调新鲜度和一致性;业务读副本强调可用性和可接受的新鲜度;分析副本允许较高延迟但不应挤压核心链路;备份副本应在可控窗口承担备份负载。目标不是所有副本的延迟恒为零,而是每个角色的 RPO/RTO 可验证。
32. 在每个实例记录身份、只读状态与 binlog 能力
SELECT @@hostname AS hostname,
@@server_uuid AS server_uuid,
@@server_id AS server_id,
@@read_only AS read_only,
@@super_read_only AS super_read_only,
@@log_bin AS log_bin;
对每台实例执行并汇总到受控拓扑清单。read_only 不能单独阻止高权限会话写入,super_read_only 提供更强约束但会影响运维和复制流程;不能在不了解平台账户行为时直接开启。
33. 检查副本是否具备级联 source 的必要条件
SHOW VARIABLES WHERE Variable_name IN (
'log_replica_updates',
'log_bin',
'gtid_mode',
'relay_log_recovery',
'read_only',
'super_read_only'
);
级联副本通常需要 log_bin=ON 与 log_replica_updates=ON,才能把应用过的事务写入自身 binlog 供下游获取。这会增加磁盘和 I/O 压力;适合将分析/远端副本从主库连接压力中隔离,但上游延迟会传递到下游。
34. 审计候选副本上正在运行的长读请求
SELECT USER, SUBSTRING_INDEX(HOST, ':', 1) AS client_host,
DB, COMMAND, TIME, STATE,
LEFT(INFO, 200) AS statement_sample
FROM information_schema.PROCESSLIST
WHERE COMMAND <> 'Sleep'
ORDER BY TIME DESC;
输出可能含 SQL 文本和用户信息,应受控保存。将 ETL、导出和重报表移出故障切换候选副本,通常比继续调 worker 更有效。不要按一次 processlist 直接封禁用户;要结合连接池、任务系统、慢日志和业务 owner。
35. 为读路由提供复制线程健康检查 SQL
SELECT CASE
WHEN (SELECT SERVICE_STATE
FROM performance_schema.replication_applier_status
LIMIT 1) <> 'ON' THEN 0
WHEN (SELECT SERVICE_STATE
FROM performance_schema.replication_connection_status
LIMIT 1) <> 'ON' THEN 0
ELSE 1
END AS replication_threads_healthy;
这只检查线程存活,不能替代最大新鲜度判定。真实读路由还要结合业务允许的延迟、GTID 或心跳差、数据库可用性与连接池行为;若使用代理或云路由,应按其官方健康检查机制实现。
36. 可选:用 pt-heartbeat 写入真实复制新鲜度心跳
pt-heartbeat \
--host=<源库主机> --user=<监控用户> \
--database=<业务库> --table=heartbeat \
--update --daemonize --log=/var/log/pt-heartbeat-source.log
pt-heartbeat 属于 Percona Toolkit,需先完成软件来源、版本与权限评估。它会持续写入一张表,表应独立于业务、具有适当索引且纳入备份;命令参数以本机 pt-heartbeat --help 为准。
37. 可选:在副本上读取 pt-heartbeat 延迟
pt-heartbeat \
--host=<副本主机> --user=<监控用户> \
--database=<业务库> --table=heartbeat \
--monitor
该检查需要 source 侧 heartbeat writer 已运行并能复制到副本。主机时间应由 NTP 或 chrony 保持同步,否则系统时钟偏差会污染结果;heartbeat 只衡量观测到的写入新鲜度,不证明全量数据一致。
38. 记录拓扑和延迟的只读巡检脚本
#!/usr/bin/env bash
set -euo pipefail
MYSQL_HOST="<副本主机>"
MYSQL_USER="<监控用户>"
MYSQL_DEFAULTS_FILE="<客户端凭据文件>"
mysql --host="${MYSQL_HOST}" --user="${MYSQL_USER}" \
--defaults-extra-file="${MYSQL_DEFAULTS_FILE}" --batch --skip-column-names \
-e "SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER
FROM performance_schema.replication_connection_status;"
mysql --host="${MYSQL_HOST}" --user="${MYSQL_USER}" \
--defaults-extra-file="${MYSQL_DEFAULTS_FILE}" --batch --skip-column-names \
-e "SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER
FROM performance_schema.replication_applier_status;"
脚本只读,不会启动、停止或修复复制。密码不应出现在 shell 参数或脚本明文中,<客户端凭据文件> 应受权限保护。运行账户应只获得读取相关 Performance Schema 的最小权限。
六、配置变更必须遵循"备份—修改—验证—回滚"
复制参数可能影响 source 和 replica。高风险点包括 mysqld 重启、GTID 变更、重建副本、切换 source 和把错误参数写入配置。生产中先选择非关键副本灰度,再按照拓扑逐台推进;不要同时改变 worker、磁盘、读路由和业务批处理,否则无法归因。对于 GitOps 或配置管理系统,最终变更必须回写声明源,避免下次发布覆盖。
39. 确认 mysqld 实际读取的配置路径
sudo mysqld --help --verbose 2>/dev/null | \
sed -n '/Default options are read from the following files/,/Variables and options/p'
不同发行版、容器镜像和托管服务的配置路径不一样。先确认读取顺序,再选择一个受配置管理的实际文件修改;不要对猜测的 /etc/my.cnf 写入后以为参数已经生效。
40. 备份实际配置文件并保留权限
sudo cp -a <实际MySQL配置文件> "<实际MySQL配置文件>.bak.$(date +%Y%m%d%H%M%S)"
sudo ls -l "<实际MySQL配置文件>" "<实际MySQL配置文件>.bak.<时间戳>"
cp -a 保留所有者、权限与时间。第二条中的 <时间戳> 要替换为刚生成的真实后缀;备份文件应位于同一受控卷或合规的配置备份位置,不能只存在易失临时目录。
41. 在支持的版本上执行配置语法校验
sudo mysqld --defaults-file=<实际MySQL配置文件> --validate-config
--validate-config 仅适用于支持该选项的 MySQL 版本,先运行 mysqld --help 确认。校验通过只说明可解析,不证明参数适合现网负载,也不能替代滚动重启后的复制与业务验证。
42. 在维护窗口重启单个副本并检查基本存活
sudo systemctl restart mysqld
sudo systemctl is-active mysqld
mysqladmin --host=127.0.0.1 --user=<本地运维用户> ping
这是高影响操作,会中断该副本本地读连接和复制。执行前从读路由摘除,确认业务副本冗余与维护窗口。mysqladmin ping 只证明服务响应;重启后仍要检查复制线程、GTID 收敛、错误日志与应用读探测。
43. 回滚配置文件并验证后再重启
sudo cp -a <实际MySQL配置文件>.bak.<时间戳> <实际MySQL配置文件>
sudo mysqld --defaults-file=<实际MySQL配置文件> --validate-config
sudo systemctl restart mysqld
这只回滚配置,不会恢复已跳过事务、已改变 source 或已重建副本的数据状态。执行前确认备份确实来自本次变更前,并且属主、权限和 include 文件关系没有丢失。GitOps 环境还应回滚配置仓库中的对应提交。
七、重建副本或更换 source:最后手段,不用猜测执行
当 source 所需 binlog 已清理、relay log 损坏不可恢复、数据差异无法安全修复,或副本基础数据不可信时,重建通常比强行追赶更安全。但它会消耗 source I/O、网络和存储,也可能影响备份窗口。先评估合格备份、GTID、版本、数据量、恢复时长、binlog 保留和读流量承接,再进入受控操作。
44. 重建前核对 source 的 binlog 保留与 GTID 模式
SHOW BINARY LOGS;
SHOW VARIABLES WHERE Variable_name IN (
'binlog_expire_logs_seconds',
'expire_logs_days',
'gtid_mode',
'enforce_gtid_consistency'
);
副本请求的 binlog 文件已经不存在时,IO 线程常会报告 1236 类错误;反复 START REPLICA 不会恢复文件。保留期要同时覆盖最大允许落后、备份恢复、审计和磁盘容量,不能只为一次告警无限延长。
45. 保存重建前的副本身份和复制元数据
SELECT @@server_uuid AS server_uuid,
@@server_id AS server_id,
@@GLOBAL.gtid_executed AS gtid_executed,
@@GLOBAL.gtid_purged AS gtid_purged;
SHOW REPLICA STATUS\G
将输出写入受控工单。恢复过程中 auto.cnf、server UUID、GTID_PURGED 和复制连接参数处理错误,可能造成 UUID 冲突、错误事务集合或连接到错误环境。不同备份工具的恢复语义不同,只能使用已经演练过的手册。
46. GTID 自动定位的复制连接示例
STOP REPLICA;
CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '<源库主机>',
SOURCE_PORT = 3306,
SOURCE_USER = '<复制用户>',
SOURCE_PASSWORD = '<复制密码>',
SOURCE_AUTO_POSITION = 1;
START REPLICA;
SHOW REPLICA STATUS\G
这是高风险命令,仅适用于 GTID 已正确启用、基础数据由合格备份恢复、source 身份经过确认的场景。密码不能保留在终端历史、脚本或工单正文,应改用受控凭据方式。执行前保存原复制配置,确认 <源库主机> 地址未指向错误环境;多源复制必须带正确 channel。
47. 重建后重新加入读路由的最低验收查询
SHOW REPLICA STATUS\G
SELECT @@GLOBAL.gtid_executed;
SELECT @@read_only, @@super_read_only;
验收必须同时覆盖:IO/SQL 线程正常、无 Last Error、GTID 差集收敛、心跳延迟达标、只读探测正常、备份和监控重新纳管。仅仅看到 Seconds_Behind_Source=0 不足以直接接回全量流量;应先灰度。
八、监控与预防:让延迟在变成 10 分钟之前被发现
监控至少区分"不可复制""延迟正在扩大""延迟稳定但超过角色阈值""读路由新鲜度不足"。Prometheus 指标命名随 mysqld_exporter、Percona exporter 或云厂商实现不同而变化,以下表达式均以实际 exporter 暴露的指标、标签和单位为准。上线前要在 Prometheus 中确认指标存在,不能复制后直接作为生产规则。
48. 监控复制线程存活
mysql_slave_status_slave_io_running == 0
or
mysql_slave_status_slave_sql_running == 0
有些 exporter 已使用 replica/source 新字段或不同 metric 名,因此以实际 exporter 暴露的指标为准。线程停止应是高优先级告警,并携带实例、channel 和最近错误链接,避免值班人员只看到一个数值。
49. 监控延迟是否在持续增长
deriv(mysql_slave_status_seconds_behind_master[10m]) > 0
该表达式适合作为趋势线索,不能单独判断复制正确性;缺失值、重置与短窗口都会影响结果。实际告警还应组合线程状态、最小持续时长、业务新鲜度阈值和实例角色。指标名与标签以实际 exporter 暴露为准。
50. 监控主机 iowait 趋势
rate(node_cpu_seconds_total{mode="iowait"}[5m])
这是 node_exporter 常见指标,表示 CPU 时间中 iowait 的比例,不等价于某块盘或 mysqld 的 I/O 瓶颈。应与磁盘队列、复制 worker、延迟趋势和同组健康副本联动分析;指标与标签以实际 exporter 暴露为准。
51. 每日复制健康巡检的最小 SQL 任务
SELECT 'connection' AS component, CHANNEL_NAME, SERVICE_STATE,
LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status
UNION ALL
SELECT 'applier' AS component, CHANNEL_NAME, SERVICE_STATE,
LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_applier_status;
这条查询适合由受控巡检账户执行,结果为空或 status 非 ON 时由监控系统告警。它不修改复制,也不替代深入排障;对于多 channel,告警必须携带具体 channel 名而不是笼统写"主从异常"。
结语
复制延迟的正确处理顺序是:先取证并区分 IO、applier、存储、事务与拓扑问题;再用最小变更恢复线程和吞吐;最后把并行复制、binlog 依赖跟踪、读流量隔离、拓扑职责和真实新鲜度监控固化为长期能力。10 分钟延迟不授权跳过事务、强制换 source 或重启所有副本。只有错误日志、复制状态、GTID 差集、worker 状态、主机指标和业务变更记录共同支持的结论,才值得进入生产处置方案。