线上读写分离环境里,主库流量没有明显变化,某个只读实例的延迟却突然从几秒变成几分钟。此时最危险的做法是直接重启复制线程,或看到 Seconds_Behind_Source 很大就跳过当前事务;这可能掩盖真正的错误和数据缺口。
十分钟初筛要回答三件事:延迟在接收线程还是 SQL 应用线程;是单个事务卡住还是副本吞吐不足;当前应等待、降读、隔离还是升级。
本文以 MySQL 8.0、GTID、异步复制和多线程副本为例,使用 source/replica 表述主库和副本。8.0.23 及以后优先使用 SHOW REPLICA STATUS,较早版本可能使用 SHOW SLAVE STATUS,执行前用 SELECT VERSION() 确认。字段以实际版本输出为准,所有 <变量名> 都是需替换的占位符。
Seconds_Behind_Source 是基于线程执行时间和源库事件时间的估算,复制未运行、刚启动、时间不同步、并行 worker 不均衡或源库没有新事务时都可能为 NULL 或失真。真正可靠的判断要结合完整复制状态、GTID 集合、worker 错误、源库写入速率、副本磁盘与锁等待。
| 时间 | 目标 | 必须留下的证据 |
|---|---|---|
| 0~1 分钟 | 确认版本、连接和状态 | 复制状态完整输出 |
| 1~3 分钟 | 区分 IO 线程和 SQL 线程 | 线程状态、错误字段、GTID 集合 |
| 3~5 分钟 | 查是否有单个 worker 或事务卡住 | worker 错误、当前事务、锁 |
| 5~7 分钟 | 看源库写入是否突增 | binlog、事务、连接和提交状态 |
| 7~9 分钟 | 看副本是否被读流量或磁盘拖慢 | processlist、InnoDB、iostat |
| 9~10 分钟 | 选择低风险动作 | 等待、限流、隔离、修复或升级 |
这条路径适合“延迟突然拉大”的初筛。数据一致性风险、复制中断、主库故障切换和跳过事务属于更高等级事件,不能只依靠十分钟快照完成决策。
命令行客户端的版本不一定等于服务器版本,SHOW 语句按服务器版本执行。先同时记录二者:
bash
#!/usr/bin/env bash set -euo pipefail MYSQL_BIN="" MYSQL_HOST="<副本地址>" MYSQL_PORT="<副本端口>" MYSQL_USER="<只读排障用户>" "$MYSQL_BIN" --version "$MYSQL_BIN" --host="$MYSQL_HOST" --port="$MYSQL_PORT" --user="$MYSQL_USER" --password --connect-timeout=5 --batch --raw --skip-column-names -e 'SELECT VERSION(), @@hostname, @@port, @@server_uuid, @@read_only, @@super_read_only;' 排障账号应通过安全方式输入密码,不要把真实密码写进命令行、脚本或聊天记录。若连接超时,先查网络、端口和账号权限,不能把连不上副本直接当成复制 SQL 线程延迟。
在副本上执行下面的查询,记录 GTID、复制线程、并行度、日志格式和只读状态:
sql
SELECT VERSION() AS mysql_version, @@hostname AS hostname, @@server_uuid AS server_uuid, @@global.gtid_mode AS gtid_mode, @@global.enforce_gtid_consistency AS enforce_gtid_consistency, @@global.binlog_format AS binlog_format, @@global.log_replica_updates AS log_replica_updates, @@global.replica_parallel_workers AS replica_parallel_workers, @@global.replica_parallel_type AS replica_parallel_type, @@global.read_only AS read_only, @@global.super_read_only AS super_read_only; MySQL 8.0 的变量名在小版本间存在更名,例如 log_slave_updates 与 log_replica_updates。若某个变量不存在,先用 SHOW VARIABLES LIKE ‘%replica%’; 和 SHOW VARIABLES LIKE ‘%slave%’; 确认当前版本,而不是直接修改配置。
副本上优先执行 SHOW REPLICA STATUS。不要只复制 Seconds_Behind_Source 一列,因为真正决定方向的是 IO、SQL、错误和位置字段的组合。
sql
SHOW REPLICA STATUSG 重点记录以下字段:
如果是早于 8.0.23 的版本,执行 SHOW SLAVE STATUSG,并把 Slave_IO_Running、Slave_SQL_Running 等旧字段映射到上述含义。不要同时在同一实例上随意切换命令,避免把输出混在一起。
下面的命令依赖 mysql 客户端的批量输出和 awk。它不会修改复制状态:
bash
#!/usr/bin/env bash set -euo pipefail MYSQL_HOST="<副本地址>" MYSQL_PORT="<副本端口>" MYSQL_USER="<只读排障用户>" mysql --host="$MYSQL_HOST" --port="$MYSQL_PORT" --user="$MYSQL_USER" --password --connect-timeout=5 --batch --raw -e 'SHOW REPLICA STATUSG' | awk -F': ' ' /^(Channel_Name|Replica_IO_Running|Replica_SQL_Running|Replica_SQL_Running_State|Seconds_Behind_Source|Last_IO_Error|Last_SQL_Error|Retrieved_Gtid_Set|Executed_Gtid_Set|Relay_Source_Log_File|Exec_Source_Log_Pos|Auto_Position|Using_Gtid):/ { print $1 "=" $2 } ' 如果版本不支持 SHOW REPLICA STATUS,替换为 SHOW SLAVE STATUS。awk 的字段提取适用于常见的 key: value 输出;多行错误信息可能被截断或分拆,因此完整原始输出仍必须保存。
可以按下面的证据快速分支:
| 现象 | 优先方向 |
|---|---|
| Replica_IO_Running=No,Last_IO_Error 有内容 | 网络、权限、源库连接、日志文件缺失 |
| IO=Yes,SQL=No,Last_SQL_Error 有内容 | SQL 应用错误、冲突、表结构或权限 |
| IO=Yes,SQL=Yes,Seconds_Behind_Source 上升 | 副本吞吐不足、长事务、锁、读流量或源库写入突增 |
| IO=Yes,SQL=Yes,Seconds 为 NULL | 复制刚启动、源库无新事务、时间或状态字段异常 |
这只是缩小范围,不是根因结论。根因必须由错误日志、worker 状态、GTID、事务和资源指标证明。
只要 Replica_IO_Running 为 No,先看错误字段和 MySQL 错误日志:
sql
SELECT CHANNEL_NAME, SERVICE_STATE, THREAD_ID, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE, LAST_ERROR_TIMESTAMP, RECEIVED_TRANSACTION_SET FROM performance_schema.replication_connection_statusG performance_schema 表可以补充通道级信息,但不是所有字段在所有 MySQL 版本都一致。查询报列不存在时,用 DESCRIBE performance_schema.replication_connection_status; 先确认列名。
错误日志位置由 log_error 配置决定。先让 MySQL 告诉你路径,再读取指定时间窗口:
sql
SHOW VARIABLES LIKE 'log_error'; SHOW VARIABLES LIKE 'log_error_verbosity'; bash
#!/usr/bin/env bash set -euo pipefail ERROR_LOG="" START_TIME="<开始时间>" END_TIME="<结束时间>" awk -v start="$START_TIME" -v end="$END_TIME" ' $0 >= start && $0 <= end {print} ' "$ERROR_LOG" | grep -Ei 'replica|slave|source|connect|access denied|fatal|error|relay|binlog' awk 按日志首列时间比较只适用于日志以可比较的 ISO 时间开头;错误日志使用其他格式时改用 journalctl、grep 或 MySQL 日志组件的实际格式。grep 没有匹配到内容不代表“没有问题”,还要检查时间格式和文件是否滚动。
在 source 上查询当前 binary log 位置。MySQL 8.0 常用 SHOW MASTER STATUS;较新版本可能提供 SHOW BINARY LOG STATUS,使用前以 SHOW HELP 或版本文档确认。
sql
SHOW MASTER STATUSG SHOW BINARY LOGS; 如果源库位置持续前进,而副本 Read_Source_Log_Pos 长时间不变,说明接收线程、网络或副本写 relay log 可能受阻。如果副本已经接收但 Executed_Gtid_Set 不前进,则问题在 SQL 应用路径。
多线程复制时,一个 worker 出错或被长事务阻塞,Seconds_Behind_Source 可能只显示整体结果。使用 performance_schema 查看协调线程和 worker:
sql
SELECT CHANNEL_NAME, THREAD_ID, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE, LAST_ERROR_TIMESTAMP FROM performance_schema.replication_applier_status_by_coordinatorG SELECT CHANNEL_NAME, WORKER_ID, THREAD_ID, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE, LAST_ERROR_TIMESTAMP, APPLYING_TRANSACTION, LAST_APPLIED_TRANSACTION, LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP FROM performance_schema.replication_applier_status_by_worker ORDER BY WORKER_IDG 某个 worker 的 LAST_ERROR_NUMBER 非零、LAST_ERROR_MESSAGE 有内容,通常比 Seconds_Behind_Source 更接近复制中断根因。多个 worker 都在运行但最后应用事务长时间不变,则需要查锁、磁盘和单个大事务。
MySQL 8.0 的 performance_schema.data_lock_waits 和 data_locks 能显示 InnoDB 锁等待关系:
sql
SELECT rw.REQUESTING_ENGINE_TRANSACTION_ID AS waiting_trx_id, rw.BLOCKING_ENGINE_TRANSACTION_ID AS blocking_trx_id, r.OBJECT_SCHEMA AS waiting_schema, r.OBJECT_NAME AS waiting_table, r.INDEX_NAME AS waiting_index, r.LOCK_TYPE AS waiting_lock_type, r.LOCK_MODE AS waiting_lock_mode, r.LOCK_DATA AS waiting_lock_data FROM performance_schema.data_lock_waits AS rw JOIN performance_schema.data_locks AS r ON r.ENGINE_LOCK_ID = rw.REQUESTING_ENGINE_LOCK_ID WHERE r.OBJECT_SCHEMA IS NOT NULL; 这条查询展示等待关系,但要得到阻塞事务的线程和 SQL,还需要继续关联 performance_schema.threads、events_statements_current 或 information_schema.innodb_trx。权限不足时结果可能为空。不要为了查锁临时关闭 performance_schema 采集。
sql
SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id, trx_rows_locked, trx_rows_modified, trx_query FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 20; SELECT THREAD_ID, EVENT_NAME, SQL_TEXT, TIMER_WAIT / 1000000000000 AS seconds_running FROM performance_schema.events_statements_current WHERE SQL_TEXT IS NOT NULL ORDER BY TIMER_WAIT DESC LIMIT 20; 副本上的读事务可能阻塞 purge 或占用资源,但不一定直接阻塞复制写入;是否冲突要看表、索引和锁隔离级别。一个很大的 trx_rows_modified 或很早的 trx_started 是线索,不是自动 kill 的依据。
在 source 上查看一组累计状态,并在数分钟后再次采样计算速率:
sql
SHOW GLOBAL STATUS WHERE Variable_name IN ( 'Com_insert', 'Com_update', 'Com_delete', 'Com_commit', 'Threads_connected', 'Threads_running', 'Binlog_bytes_written', 'Binlog_commits', 'Binlog_group_commits', 'Binlog_cache_use', 'Binlog_cache_disk_use' ); 这些是累计计数器,单次读数不能说明当前速率。Binlog_bytes_written 或提交计数在窗口内快速增长,说明源库写入强度可能上升;Threads_running 上升则要继续查锁、慢 SQL 和连接池,不能直接等同于复制延迟。
sql
SELECT trx_id, trx_started, TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS age_seconds, trx_state, trx_mysql_thread_id, trx_rows_locked, trx_rows_modified, trx_query FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 20; 一个长事务可能造成大 binlog 事务、锁等待和副本应用延迟。不要看到 age_seconds 大就直接终止;先确认连接归属、业务影响、是否为在线 DDL 或批处理,以及 kill 后事务回滚可能带来的额外时间。
sql
SELECT p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM information_schema.PROCESSLIST AS p WHERE p.COMMAND <> 'Sleep' ORDER BY p.TIME DESC; PROCESSLIST 的 TIME 是当前状态持续时间,不一定是语句总耗时;INFO 可能被截断。需要执行计划时,应在低风险环境对同一 SQL 使用 EXPLAIN 或 EXPLAIN ANALYZE,不要在生产副本上对大表随意执行会真正运行语句的分析操作。
只读副本通常同时承担查询流量。复用上一节的 PROCESSLIST 查询,在副本上执行并按同一时间窗口观察。长时间 Sending data 不一定代表网络发送,它可能表示执行扫描或读取数据。大量查询、临时表、排序和 buffer pool miss 会让复制 SQL 线程拿不到 CPU、锁或磁盘。
sql
SHOW GLOBAL STATUS WHERE Variable_name IN ( 'Threads_running', 'Created_tmp_tables', 'Created_tmp_disk_tables', 'Innodb_buffer_pool_reads', 'Innodb_buffer_pool_read_requests', 'Innodb_row_lock_current_waits', 'Innodb_row_lock_time', 'Innodb_os_log_pending_fsyncs', 'Innodb_data_pending_reads', 'Innodb_data_pending_writes', 'Innodb_buffer_pool_pages_dirty' ); Created_tmp_disk_tables、pending reads/writes 和 row lock 相关计数需要与时间窗口比较。累计值高不代表当前一定异常。若读查询导致磁盘延迟或锁等待上升,应优先做流量降级或把查询迁移到其他副本;这属于业务变更,需要确认连接池和路由回滚方式。
bash
#!/usr/bin/env bash set -euo pipefail iostat -xz 1 10 df -hT df -ih iostat 来自 sysstat,字段含义以本机版本为准。重点看副本承载 MySQL 数据目录、relay log 和临时目录的设备。df -hT 与 df -ih 分别检查字节空间和 inode;磁盘快满或 inode 用尽都可能让 relay log 写入异常。
sql
SHOW VARIABLES WHERE Variable_name IN ( 'server_id', 'server_uuid', 'gtid_mode', 'enforce_gtid_consistency', 'binlog_format', 'sync_binlog', 'innodb_flush_log_at_trx_commit', 'replica_parallel_workers', 'replica_parallel_type', 'replica_preserve_commit_order', 'replica_pending_jobs_size_max', 'replica_transaction_retries' ); 并行 worker 数量、提交顺序和事务重试策略会影响应用吞吐与一致性语义。不要为了追延迟直接把 replica_parallel_workers 调到最大;需要先看 CPU、磁盘、锁和事务冲突,修改后还要观察回放顺序与错误。
sql
SHOW VARIABLES WHERE Variable_name LIKE '%replicate%' OR Variable_name LIKE '%binlog_do%' OR Variable_name LIKE '%binlog_ignore%'; SHOW CREATE TABLE <库名>.<表名>G 过滤器差异可能使副本故意不应用某些库表;表结构差异则可能导致 SQL 线程报错。SHOW CREATE TABLE 只读,但 <库名> 和 <表名> 必须替换为明确对象,不能把用户输入未经校验拼接到自动脚本中。
sql
SELECT @@global.read_only AS read_only, @@global.super_read_only AS super_read_only, @@session.sql_log_bin AS sql_log_bin; SELECT USER, HOST, COMMAND, COUNT(*) AS connections FROM information_schema.PROCESSLIST GROUP BY USER, HOST, COMMAND ORDER BY connections DESC; 副本被误写可能产生复制冲突或消耗资源。read_only 和 super_read_only 的具体行为与账号权限有关,不能只看变量名下结论。任何修改只读状态的动作都属于高风险操作,必须先确认切换流程、备份和回滚。
sql
SELECT @@global.gtid_executed AS server_gtid_executed, @@global.gtid_purged AS server_gtid_purged; SHOW REPLICA STATUSG Retrieved_Gtid_Set 代表副本接收过的事务集合,Executed_Gtid_Set 代表已执行集合。两者存在明显差异时,说明事件已经进入副本但尚未全部应用。GTID 集合是区间字符串,不能简单用字符串长度当作事务数;应使用 MySQL 的 GTID 函数或专门工具解析,并注意不同 UUID 和区间。
如果需要验证某个明确 GTID 是否已经执行,可以在副本上使用 WAIT_FOR_EXECUTED_GTID_SET。它会等待,属于有阻塞时间的检查,必须设置超时:
sql
SELECT WAIT_FOR_EXECUTED_GTID_SET( '<源库UUID>:<事务编号>', 5 ) AS wait_seconds; 返回 0 表示在超时时间内已满足,返回 1 表示超时,返回 NULL 表示参数或执行状态异常。不要把未知的 GTID 字符串直接填入生产查询;先从 SHOW REPLICA STATUS 的实际输出中确认。等待本身不会修复复制,只能验证执行进度。
下面脚本假设 MySQL 8.0.23 及以后,默认在副本执行,收集复制状态、worker、锁、事务和系统 I/O。它不执行 STOP REPLICA、START REPLICA、KILL 或配置修改。
bash
#!/usr/bin/env bash set -euo pipefail MYSQL_HOST="<副本地址>" MYSQL_PORT="<副本端口>" MYSQL_USER="<只读排障用户>" OUT_DIR="/tmp/mysql-replica-evidence-$(date +%Y%m%d%H%M%S)" mkdir -p "$OUT_DIR" umask 077 run_mysql() { mysql --host="$MYSQL_HOST" --port="$MYSQL_PORT" --user="$MYSQL_USER" --password --connect-timeout=5 --batch --raw "$@" } run_mysql -e 'SELECT NOW(), VERSION(), @@hostname, @@server_uuid;' > "$OUT_DIR/identity.txt" run_mysql -e 'SHOW REPLICA STATUSG' > "$OUT_DIR/replica-status.txt" run_mysql -e ' SELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE, LAST_ERROR_TIMESTAMP, APPLYING_TRANSACTION, LAST_APPLIED_TRANSACTION FROM performance_schema.replication_applier_status_by_worker ORDER BY WORKER_ID; ' > "$OUT_DIR/worker-status.txt" run_mysql -e ' SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id, trx_rows_locked, trx_rows_modified, trx_query FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 50; ' > "$OUT_DIR/innodb-trx.txt" run_mysql -e 'SHOW FULL PROCESSLIST;' > "$OUT_DIR/processlist.txt" run_mysql -e " SHOW GLOBAL STATUS WHERE Variable_name IN ( 'Threads_running', 'Created_tmp_disk_tables', 'Innodb_row_lock_current_waits', 'Innodb_os_log_pending_fsyncs', 'Innodb_data_pending_reads', 'Innodb_data_pending_writes', 'Innodb_buffer_pool_pages_dirty' ); " > "$OUT_DIR/status.txt" iostat -xz 1 10 > "$OUT_DIR/iostat.txt" df -hT > "$OUT_DIR/df-h.txt" df -ih > "$OUT_DIR/df-i.txt" tar -C "$(dirname "$OUT_DIR")" -czf "$OUT_DIR.tar.gz" "$(basename "$OUT_DIR")" printf 'evidence archive: %s ' "$OUT_DIR.tar.gz" 脚本中的密码仍由 mysql 客户端交互读取,不能在无人值守环境直接使用。若账号没有 performance_schema 权限,脚本可能在中途失败;可把只读查询拆开执行并记录失败项。压缩包包含 processlist 和 SQL 文本,属于敏感运维数据,应限制权限和保存期限。
| 现象 | 先看什么 | 下一步 |
|---|---|---|
| Replica_IO_Running=No | Last_IO_Error、源库连接、日志保留、relay log 磁盘 | 查认证、网络、日志文件和空间;证据清楚前不要 RESET REPLICA 或重新指向 source |
| Replica_SQL_Running=No | Last_SQL_Error、Last_SQL_Errno、worker、当前 GTID | 查表结构、唯一键、权限、存储引擎和锁;不要把错误直接跳过 |
| 两线程运行但延迟上升 | source binlog/提交速率与 replica 应用进度 | 判断源库写入突增,还是副本读流量、磁盘、锁或并行冲突 |
| Seconds_Behind_Source=NULL | 两线程状态、错误字段、GTID 集合、source 是否有新事务 | 线程正常且无新事务时,用明确 GTID 或位点做验证 |
线程报错时必须保存错误号、错误文本、worker 状态和 GTID。跳过事务会让副本与 source 产生差异;只有完成数据校验、取得负责人批准并准备补偿方案后,才进入专门的跳过或重建流程。一次 SHOW STATUS 的累计值不能比较速率,应间隔 30~60 秒重复采样。
如果证据表明副本读查询导致磁盘、CPU、锁或临时表压力,可以先在连接池、代理或服务发现层把该实例标记为不可读。这个动作比停止复制更容易回滚,但仍可能影响连接分布和整体容量。
执行前检查:
执行后验证错误率、连接数、Threads_running、iostat 和复制应用进度。不要只看代理显示的权重下降。
如果确认某个查询阻塞复制或耗尽副本资源,可以通过应用层取消、连接池超时或经授权的 KILL QUERY 处理。KILL 是有风险的,查询可能持有事务或触发回滚。
sql
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE ID = <线程ID>G KILL QUERY <线程ID>; <线程ID> 必须来自当前实例、当前时间窗口的 PROCESSLIST,并由有权限人员确认。KILL QUERY 只终止当前语句,连接可能仍然存在;若要 KILL CONNECTION,风险更大。执行后应查原事务是否回滚、锁是否释放、复制 worker 是否继续。
如果之前只是计划性 STOP、网络已经恢复、错误原因已消除,并且保存了状态,才考虑 START REPLICA。不要把 START REPLICA 当作所有延迟问题的通用修复。
sql
START REPLICA; SHOW REPLICA STATUSG START REPLICA 可能同时启动 IO 和 SQL 线程,具体行为按版本和参数确定。执行后至少观察数个采样窗口,确认两个线程持续运行、Last_Error 为空、GTID 执行集合前进、延迟不再扩大,并检查副本资源是否被回放冲高。
STOP REPLICA 会让副本停止接收或应用事务,具体停止哪个线程取决于是否指定 IO_THREAD 或 SQL_THREAD。它可能扩大延迟、占满 relay log,也可能影响故障切换可用性。只有在要保护副本、处理明确错误或执行受控维护时使用。
sql
SHOW REPLICA STATUSG STOP REPLICA SQL_THREAD; SHOW REPLICA STATUSG 执行前保存完整状态、确认 relay log 剩余空间、确认不会把该实例误当作健康副本,并通知依赖方。执行后记录停止时间和原因。恢复使用 START REPLICA SQL_THREAD,并按 GTID、worker 和业务读流量验证。
跳过事务会改变 Executed_Gtid_Set 与 source 的数据语义。GTID 模式下使用 sql_replica_skip_counter 通常不是合适的通用手段;不同复制模式和版本的处理方式不同,可能需要注入空事务、修复数据后重新执行或从备份重建副本。
任何跳过动作至少需要:
如果事务是 DDL、权限变更、账务写入或关键配置变更,通常不应在值班电话中直接跳过。更安全的选择可能是隔离副本、重建副本或先修复数据。
bash
#!/usr/bin/env bash set -euo pipefail MYSQL_HOST="<副本地址>" MYSQL_PORT="<副本端口>" MYSQL_USER="<只读排障用户>" OUT_FILE="/tmp/replica-before-change-$(date +%Y%m%d%H%M%S).txt" mysql --host="$MYSQL_HOST" --port="$MYSQL_PORT" --user="$MYSQL_USER" --password --connect-timeout=5 --batch --raw -e ' SELECT NOW(), VERSION(), @@hostname, @@server_uuid; SHOW REPLICA STATUSG SHOW VARIABLES LIKE "replica%"; SHOW VARIABLES LIKE "gtid%"; ' > "$OUT_FILE" chmod 600 "$OUT_FILE" printf 'saved: %s ' "$OUT_FILE" 这是变更前状态记录,不是数据备份。如果要做表修复、重建副本或切换,仍需按数据库备份策略取得可恢复备份或快照。复制状态文件不能替代备份。
sql
SHOW REPLICA STATUSG SHOW VARIABLES LIKE 'source%'; SHOW VARIABLES LIKE 'master%'; SHOW VARIABLES LIKE 'report%'; CHANGE REPLICATION SOURCE TO 会改变连接、日志位置、GTID 自动定位或 TLS 参数,是高风险变更。不要用网上复制的整条命令覆盖所有参数,尤其不要在 GTID 自动定位环境中随意指定 file/position。只有明确知道当前模式、备份和回滚方式时才执行。
复制线程恢复后,按顺序验证,而不是只看一行 Seconds_Behind_Source:
可以使用如下只读 SQL 做连续验证:
sql
SELECT NOW() AS checked_at; SHOW REPLICA STATUSG SELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE, LAST_APPLIED_TRANSACTION, LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP FROM performance_schema.replication_applier_status_by_worker ORDER BY WORKER_ID; 需要把每次执行的时间和结果保存下来,才能判断是前进、停滞还是反复。若错误字段为空但 GTID 不前进,继续查源库是否有新事务、副本是否正在等待大事务提交、是否存在读流量或设备瓶颈。
如果要判断 GTID、线程状态和累计计数是前进还是停滞,应在同一实例每 30 秒重复执行一次 SHOW REPLICA STATUS 和关键状态查询,至少持续十分钟。运行时记录采样时间,不要用一次 SHOW GLOBAL STATUS 的累计值比较速率。一个只读排障连接通常足够,避免在多台实例同时启动大量采集连接;输出包含错误字段和主机信息,应按敏感数据处理。
出现以下任一情况,应尽快升级到数据库负责人或切换负责人:
“再等五分钟”只有在复制线程正常、GTID 差距在缩小、磁盘和锁压力可控时才是合理选择。线程正常但差距持续扩大,等待只是让恢复成本更高。
主从延迟突然拉大时,最有效的动作不是寻找一条神奇命令,而是按顺序把范围缩小:
复制状态 → I/O 线程还是 SQL 线程 → GTID 已接收还是已执行 → worker、锁还是大事务 → source 写入还是 replica 资源 → 低风险缓解还是数据库级故障流程
只要保留完整状态、错误字段、GTID、事务和资源证据,就能避免把一个延迟数字误判成单一根因。十分钟内不一定能修好所有复制故障,但应该能明确下一步是安全等待、隔离读流量、处理已确认的异常,还是停止继续尝试并升级。
全部0条评论
快来发表一下你的评论吧 !