确认大事务回滚拖垮io和cpu需查show engine innodb status中rolling back事务及undo log量级,结合innodb_trx与processlist定位源头,避免盲目kill,应限流写入、调低io_capacity并保障buffer_pool_size。

确认是不是大事务回滚在拖垮IO和CPU
直接看 SHOW ENGINE INNODB STATUS\G 的 TRANSACTIONS 部分,重点找 ROLLING BACK 状态的事务,以及 undo log 相关描述。如果看到类似 rollback of 123456789 rows 或 undo log records: 2.4M 这种量级,基本就是它了。此时 mysqld 进程的 CPU 使用率会持续偏高(不是尖峰而是稳定在 70%+),同时 iostat -dx 1 显示磁盘 await 和 %util 持续接近 100%,尤其是写 I/O(w/s、wkB/s)异常高。
查清哪个事务在回滚、干了什么
仅靠 INNODB STATUS 不足以定位原始 SQL,得结合 information_schema.INNODB_TRX 和 PROCESSLIST:
SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query FROM information_schema.INNODB_TRX WHERE trx_state = 'ROLLING BACK';- 用返回的
trx_mysql_thread_id去查information_schema.PROCESSLIST,看INFO字段是否还残留着原始语句(有时已为空,但USER和HOST能帮你缩小应用范围) - 如果事务已断开连接,
trx_query为空,就只能靠时间点 + 应用日志反推:查slow_log或应用层埋点中最近 5–10 分钟内执行时间长、影响行数多的UPDATE/DELETE语句
别急着 kill,先评估代价
对正在回滚的大事务执行 KILL 并不总是“解药”,反而可能延长恢复时间:
-
KILL后 MySQL 仍需完成回滚,只是换一种方式继续——你只是中断了客户端连接,InnoDB 内部回滚不会停 - 回滚本身是单线程操作,且无法并行;强行
KILL可能导致后续崩溃恢复更久(尤其在未开启innodb_fast_shutdown=0时) - 真正有效的止损动作是:立刻停止该业务线所有新写入,防止 undo log 进一步膨胀;检查
innodb_undo_tablespaces是否足够,避免 undo 表空间写满卡死
回滚期间如何降低系统冲击
回滚过程不可跳过,但可以减缓对业务的影响:
- 临时调低
innodb_io_capacity(比如从 2000 改为 500),让回滚写入更“温和”,减少抢占其他查询的 IO 带宽 - 确保
innodb_buffer_pool_size足够大(建议 ≥ 总数据量的 70%),避免回滚过程中频繁刷脏页加剧 IO - 如果使用的是 MySQL 5.7+,检查
innodb_rollback_on_timeout是否为OFF(默认值),避免超时自动触发回滚放大问题 - 监控
SHOW GLOBAL STATUS LIKE 'Innodb_rows_deleted'和Innodb_rows_updated的速率变化,判断回滚进度是否正常(应缓慢下降,而非卡住)
PROCESSLIST 里,也不进慢日志,而是在 InnoDB 底层静默消耗资源。最常被忽略的是 undo log 的物理写放大——1 行更新可能生成数十字节 undo 记录,回滚时又要重读、解析、撤销,CPU 和 IO 双重吃紧。











