metadata锁导致从库sql线程卡在waiting for table metadata lock,根本原因是ddl持有的mdl阻塞后续dml回放,需通过performance_schema.metadata_locks和show processlist交叉验证定位,而非仅依赖seconds_behind_master。

Large Metadata锁导致SQL线程卡住
主库执行 ALTER TABLE 等 DDL 时,会先加元数据锁(MDL),等事务提交后才写入 binlog;从库 SQL 线程回放该事件时,必须等待所有依赖事务完成,且自身也会触发同级别 MDL —— 这会导致后续所有事务排队,Seconds_Behind_Master 骤增,但 Slave_SQL_Running_State 可能卡在 Waiting for table metadata lock,而非明显报错。
- 典型现象:从库
SHOW PROCESSLIST中 SQL 线程状态长期为Waiting for table metadata lock,同时SHOW SLAVE STATUS\G显示Slave_SQL_Running: Yes但延迟持续上涨 - 根本原因不是“慢”,而是阻塞:DDL 不是耗时操作本身拖慢复制,而是它持有的 MDL 阻塞了其他 DML 的回放
-
pt-online-schema-change或gh-ost生成的变更不触发长持有 MDL,因为它们用小事务 + 触发器模拟,绕过了原生 DDL 的锁机制 - MySQL 8.0.12+ 支持
ALGORITHM=INSTANT的部分列变更(如加虚拟列、改列注释),这类操作不锁表也不生成大 relay log,可直接使用
如何确认是Metadata锁而非其他延迟
不能只看 Seconds_Behind_Master。真卡在 MDL 上时,这个值可能失真甚至为 0 —— 因为 SQL 线程还在运行,只是被锁挂起。必须交叉验证:
- 查从库线程:
SHOW PROCESSLIST找到system user身份的线程,观察其State字段是否为Waiting for table metadata lock - 查锁信息:
SELECT * FROM performance_schema.metadata_locks WHERE OWNER_THREAD_ID != (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_COMMAND = 'Sleep') ORDER BY LAST_UPDATE_TIMESTAMP DESC LIMIT 5; - 对比主库 DDL 时间:在主库查
SELECT @@global.gtid_executed;,再在从库比对Retrieved_Gtid_Set和Executed_Gtid_Set,若两者差一个 GTID 且该 GTID 对应的是ALTER,基本锁定问题
MySQL 5.7/8.0 下绕过Large Metadata的实操路径
线上已卡住?优先止损;未发生?提前规避。两类动作完全不同:
- 已卡住时,**不要 stop slave**:这会让 SQL 线程释放锁但中断复制位置,重启后仍要重试该 DDL,大概率再次卡住
- 已卡住时,**可 kill 掉从库上持有 MDL 的无关连接**(比如某个长事务的业务连接),用
KILL CONNECTION {id}释放锁源;但不能 kill SQL 线程本身 - 未卡住时,主库 DDL 必须用
pt-online-schema-change --chunk-size=1000 --max-load="Threads_running=25" --critical-load="Threads_running=50"控制压力,避免触发从库资源争抢 - 8.0+ 环境下,对支持
INSTANT的变更,显式指定:ALTER TABLE t ADD COLUMN c2 INT COMMENT 'new col' ALGORITHM=INSTANT;,否则默认仍走COPY
为什么set global read_only=ON不能解决这个问题
很多人误以为给从库设 read_only=ON 就能防住 MDL 冲突,其实完全无效 —— read_only 只限制普通用户写入,不影响 SQL 线程自身的回放行为,它照样会申请 MDL、照样会被阻塞。真正起作用的是架构层隔离:
- DDL 必须走独立通道:通过运维平台审批、灰度发布,禁止开发直连主库执行
ALTER - 从库禁止任何非复制写入:确保
super_read_only=ON(不只是read_only),防止人为或脚本意外写入干扰锁状态 - 监控必须覆盖 MDL:用
performance_schema.metadata_locks+ Prometheus 抓取metadata_lock_wait_seconds指标,而不是只盯Seconds_Behind_Master
真实环境里,DDL 引发的延迟往往伴随“看起来没报错、查不到原因、重启无效”三连,核心就在于 MDL 是隐式、跨会话、不落日志的锁。盯住 performance_schema.metadata_locks 和 SQL 线程的 State,比任何延迟数值都可靠。











