找回密码
立即注册
搜索
发回帖 发新帖

4892

积分

0

好友

622

主题
发表于 1 小时前 | 查看: 4| 回复: 0

"主从延迟 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 需要分别确认。

4. 用 Performance Schema 读取结构化线程状态

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 状态、主机指标和业务变更记录共同支持的结论,才值得进入生产处置方案。




上一篇:腾讯元器官宣11月停运:基于混元大模型的AI智能体平台为何关停?
下一篇:Stitch 配合 Claude Code 建站:先静态后动画更稳妥
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-16 02:13 , Processed in 0.132897 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表