mysql从库滚动升级前须确认seconds_behind_master为0且io/sql线程均为yes,gtid模式下还需retrieved_gtid_set与executed_gtid_set一致,并用master_pos_wait校验追平;升级时先stop slave io_thread,再mysqladmin shutdown,启停后分步start slave io_thread和sql_thread;跨版本需预检并可能dump/load mysql系统库;按延迟分批升级,每批≤2实例,加sleep及监控埋点。

滚动升级前必须确认的复制状态
MySQL从库滚动升级不是简单重启,核心前提是复制链不能断。升级前必须确保每个从库的 Seconds_Behind_Master 为 0,且 Slave_IO_Running 和 Slave_SQL_Running 均为 Yes。用 SHOW SLAVE STATUS\G 检查时,还要注意 Retrieved_Gtid_Set 和 Executed_Gtid_Set 是否一致(GTID 模式下),否则强行升级可能跳过事务或重复执行。
常见错误是只看 Seconds_Behind_Master == 0 就认为就绪——但若主库刚写入大事务,从库 SQL 线程还在 apply 中,Seconds_Behind_Master 可能短暂归零后又飙升。建议加一层校验:SELECT MASTER_POS_WAIT('binlog.000001', 123456789, 30)(用 SHOW MASTER STATUS 当前位点)确认已完全追平。
升级脚本中必须停用复制再启停 mysqld
直接 kill -9 或 systemctl restart mysql 会丢失复制上下文,尤其 GTID 模式下容易导致 Could not execute Write_rows event on table 错误。正确流程是:先停复制,再关进程,升级二进制,再启进程,最后手动 start slave。
- 停复制命令必须用
STOP SLAVE IO_THREAD(不是STOP SLAVE),保留 SQL 线程继续消费 relay log,避免 relay log 积压 - 关闭 mysqld 必须用
mysqladmin shutdown -u root -p --socket=/var/lib/mysql/mysql.sock,不依赖 systemd,避免信号处理不一致 - 启动后不要自动 start slave,脚本需显式执行
START SLAVE IO_THREAD,等几秒再START SLAVE SQL_THREAD,降低并发冲突风险
版本兼容性决定是否要 dump/load 元数据
MySQL 主版本跨升(如 5.7 → 8.0)必须运行 mysql_upgrade,但该工具在 8.0.16+ 已废弃,改由 mysqld 启动时自动执行。不过,如果从库启用了 innodb_file_per_table=OFF 或存在旧版分区表,仍可能触发 Table upgrade required 报错并卡住启动。
稳妥做法是:升级前在单个从库上预演,用 mysqld --upgrade=FORCE 启动(仅测试),观察 error log 中是否有 InnoDB: Upgrade is required 类提示。若有,说明需提前导出 mysql 系统库(mysqldump --skip-lock-tables --single-transaction -u root mysql > mysql.sql),升级后再导入。
滚动节奏控制:按延迟分组 + 并发数硬限
批量升级不是“一起 reload”,而是按复制延迟分批次(如延迟 ≤5s、6–30s、>30s),每批最多并发升级 2 个实例。否则主库网络/IO 压力突增,可能拖慢所有从库的 IO_THREAD。
脚本里必须内置等待逻辑:
- 每升级完一个从库,用
SELECT SLEEP(5)或sleep 5避免瞬时密集连接 - 检查
SHOW PROCESSLIST中是否存在大量Waiting for master to send event,有则暂停下一批 - 记录每个实例的升级时间戳到本地文件(如
/tmp/rolling-upgrade.log),便于故障时定位中断点
最易被忽略的是监控埋点——升级脚本本身不报错,不代表业务无感。务必在脚本开头和结尾调用 curl -X POST 'http://monitor/api/v1/alert?msg=mysql_slave_upgrading' 类接口,让值班系统知道“此刻正在动生产从库”。











