只读实例数量超过10个时不能批量重启,因各实例复制延迟、SQL线程状态及relay log位置不一致,批量执行STOP SLAVE+重启易导致GTID不连续或binlog position错位,引发ERROR 1236等同步失败。

只读实例数量超过10个时,为什么不能批量重启?
因为每个只读实例的复制延迟、SQL线程状态、relay log位置都不一致,批量执行 STOP SLAVE + 重启会导致部分实例卡在 Waiting for source to send event 或 Retrying transaction 状态,后续 START SLAVE 可能因 GTID 不连续或 binlog position 错位直接报错 ERROR 1236 (HY000)。
真实场景中,常见错误现象是:5个只读实例里有2个启动后 Seconds_Behind_Master 持续为 NULL,SHOW SLAVE STATUS\G 显示 Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates,但实际已停止同步。
- 必须逐个检查每个只读实例的
Exec_Master_Log_Pos和Relay_Master_Log_File,确认与主库SHOW MASTER STATUS的File/Position对齐 - 若存在 GTID 模式,先运行
SELECT @@gtid_executed;对比主从差集,用SET GTID_NEXT='xxx'; BEGIN; COMMIT;补空事务(仅限无业务写入窗口) - 避免在
read_only=ON未生效前就关闭 SQL 线程——某些旧版本(如 5.7.28)在read_only切换后仍允许 SUPER 用户执行 DML,导致误写
升级过程中如何避免主库被只读实例拖慢?
主库在升级期间仍需持续接收写入,而大量只读实例同时重放 relay log 会争抢 I/O 和 CPU 资源,尤其当它们都卡在同一个大事务(如 ALTER TABLE)上时,主库 binlog 写入延迟可能从毫秒级升至秒级,触发应用端连接超时。
关键控制点是限制只读实例的复制并发度和节奏。不要依赖默认的 slave_parallel_workers 值(MySQL 8.0 默认为 4,但 10+ 实例集体启用会压垮主库磁盘)。
- 升级前统一设置:
SET GLOBAL slave_parallel_workers = 1;,并写入 my.cnf 防止重启丢失 - 对 relay log 已追平的实例,手动执行
STOP SLAVE IO_THREAD;,只保留 SQL 线程消化积压;等主库压力回落再恢复 IO - 监控主库
SHOW PROCESSLIST中状态为Writing to net的线程数,超过 30 个就暂停下一批只读实例升级
只读实例配置文件容易忽略的三个硬编码路径
多只读实例常共用一套 systemd service 模板(如 mysqld@.service),但升级后容易因路径未更新导致启动失败,错误信息通常是 Failed at step EXEC spawning /usr/sbin/mysqld: No such file or directory 或 Can't open shared library 'auth_socket.so'。
根本原因是:只读实例的 my.cnf 或环境变量里硬编码了旧版二进制路径,且未随主库升级同步更新。
- 检查每个实例的
my.cnf中plugin_dir是否指向新版/opt/mysql-8.0.39/lib/plugin/(不是旧版/usr/lib64/mysql/plugin/) - 确认
mysqld@.service的EnvironmentFile=-/etc/sysconfig/mysqld-%i文件里MYSQLD_BIN指向/opt/mysql-8.0.39/bin/mysqld,而非/usr/sbin/mysqld - 验证
LD_LIBRARY_PATH是否包含新版 lib 路径,例如export LD_LIBRARY_PATH="/opt/mysql-8.0.39/lib:$LD_LIBRARY_PATH",否则mysqld --version可能报libstdc++.so.6: version `GLIBCXX_3.4.29' not found
升级后必须验证的两个隐藏一致性断点
只读实例数量多时,即使所有 Seconds_Behind_Master 显示为 0,也不代表数据完全一致。MySQL 复制存在两类静默不一致:GTID gap 导致的逻辑跳过,以及 binlog_format=STATEMENT 下函数调用结果差异。
最容易被跳过的验证是:主库执行过 CREATE USER 或 GRANT 后,只读实例的 mysql.user 表未同步更新,但复制线程状态正常——因为权限变更不写 binlog(除非开启 log_bin_trust_function_creators)。
- 对每个只读实例运行:
SELECT COUNT(*) FROM mysql.user;并与主库比对;再查SELECT User,Host,authentication_string FROM mysql.user ORDER BY User,Host LIMIT 5;抽样核对哈希值 - 检查
SELECT * FROM performance_schema.replication_applier_status_by_coordinator;中APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP是否全部非 NULL(NULL 表示该事务未真正应用) - 若使用
binlog_format=ROW,用mysqlbinlog --base64-output=DECODE-ROWS -v解析最近 relay log,确认mysql.db、mysql.tables_priv等系统表变更是否完整记录
升级完成不等于结束。当只读实例超过 10 个时,最后一个实例启动后,必须等待至少 2 个 binlog rotation 周期(通常 2 × expire_logs_days),再执行全量校验——因为 relay log 清理策略可能让早期不一致被掩盖。


















