磁盘空间不足会触发MySQL保护机制导致事务悬挂,需先用df -h检查/var/lib/mysql分区及ibtmp1路径使用率是否≥95%,再查error.log中OS error code 28等错误,最后通过INNODB_TRX筛选长时间RUNNING却无进展的事务。

磁盘空间不足本身不会直接导致事务挂起,但会触发 MySQL 的保护机制(如写 binlog 失败、无法扩展 undo log、临时文件写入失败),进而让事务卡在“等待 I/O”或“等待锁”状态,表现为 trx_state = 'RUNNING' 却无实际执行进展——这正是悬挂事务(zombie transaction)的典型特征。清理这类事务不能只看“时间长”,得看“是否真在干活”。
怎么确认是磁盘不足引发的悬挂事务
先查磁盘和错误日志,别急着 KILL:
- 用
df -h检查/var/lib/mysql所在分区是否Use% ≥ 95%;特别注意ibtmp1(临时表空间)所在路径,它不走datadir但可能单独占满磁盘 - 查 MySQL 错误日志:
tail -n 100 /var/log/mysql/error.log,重点搜OS error code 28(No space left on device)、Failed to write to binlog、Cannot create temporary file - 再查悬挂事务:
SELECT trx_id, trx_state, trx_started, trx_query, trx_mysql_thread_id FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING' AND trx_started —— 这类才是真可疑对象
为什么不能直接定时 KILL 所有“老事务”
盲目 KILL 会破坏业务一致性,比如一个正在做批量导入的长事务,trx_query 可能为空(因处于锁等待或内部阶段),但它不是僵尸。真正该杀的是:
- 状态为
RUNNING且trx_query为空或为NULL - 启动时间早于某个阈值(如 5 分钟),且期间无任何
trx_operation_state变化(需结合INFORMATION_SCHEMA.INNODB_TRX和PROCESSLIST对比) - 对应线程在
SHOW PROCESSLIST中显示为Sleep或Locked,而非Query或Updating
所以存储过程里必须加 trx_query IS NULL OR trx_query = '' 判断,不能只靠 trx_started。
如何安全自动清理:事件 + 存储过程 + 日志闭环
推荐用 MySQL 原生 EVENT 调度,但必须满足三个前提:调度器开启、账号有 EVENT 权限、操作留痕可追溯。
- 开启调度器(永久):在
my.cnf的[mysqld]段加event_scheduler = ON,重启生效 - 授权账号:
GRANT EVENT ON mydb.* TO 'cleaner'@'localhost'(别给*.*,最小权限原则) - 建带日志的存储过程(示例只删 5 分钟以上无查询的事务):
DELIMITER $$ CREATE PROCEDURE cleanup_zombie_trx() BEGIN DECLARE done INT DEFAULT FALSE; DECLARE v_trx_id VARCHAR(18); DECLARE v_thread_id BIGINT; DECLARE cur CURSOR FOR SELECT trx_id, trx_mysql_thread_id FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING' AND trx_started < NOW() - INTERVAL 5 MINUTE AND (trx_query IS NULL OR trx_query = ''); DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; <p>OPEN cur; read_loop: LOOP FETCH cur INTO v_trx_id, v_thread_id; IF done THEN LEAVE read_loop; END IF; INSERT INTO cleanup_log VALUES (NOW(), v_thread_id, v_trx_id, 'killed'); KILL v_thread_id; END LOOP; CLOSE cur; END$$ DELIMITER ; - 建事件调用它:
CREATE EVENT ev_cleanup_zombie ON SCHEDULE EVERY 30 SECOND DO CALL cleanup_zombie_trx()
磁盘清理后事务仍卡住?检查 undo 表空间和 binlog
即使删了文件腾出空间,InnoDB 的 undo_001 文件可能已损坏或膨胀到无法收缩,binlog 也可能因写入失败而卡住复制位点。这时要:
- 确认
innodb_undo_tablespaces是否为 0(MySQL 8.0.23+ 默认 2),若设为 0 则 undo 在系统表空间内,无法在线 shrink,只能重建实例 - 运行
SHOW BINARY LOGS;看最老 binlog 是否远早于当前时间,若是,用PURGE BINARY LOGS BEFORE '2026-04-10 00:00:00';清理(注意主从延迟) - 检查
innodb_max_undo_log_size是否过小导致频繁分配新 undo 段,建议设为 2G+(需重启)
真正棘手的不是“怎么删”,而是“删完之后 undo 和 binlog 是否还带着病灶继续拖慢后续事务”——这点常被忽略。


















