undo log重放是纯cpu密集型操作,需逐行解码、定位、校验、写入buffer pool并更新索引;purge滞后与锁批量释放进一步加剧cpu争用,导致innodb并发机制被串行化。

回滚本身不直接吃CPU,高CPU是Undo Log重放、Purge线程争抢和锁清理过程引发的连锁反应。
Undo Log重放是纯CPU密集型操作
MySQL回滚不是“撤销SQL”,而是按Undo Log里记录的旧值逐行覆盖——每条记录都要解码、定位、校验、写入Buffer Pool、更新页哈希、刷脏页。这个过程完全在内存中进行,不依赖磁盘IO,但极度消耗CPU。
-
TRX_ROWS_MODIFIED超过10万时,Undo Log可能达数百MB,重放需数百万次内存操作 - 若事务修改了带二级索引的表,每行变更还要回滚所有相关索引项,CPU开销翻倍
- MySQL 8.0+ 默认启用
innodb_parallel_read_threads,但回滚仍为单线程串行执行,无法并行加速
Purge线程被拖垮后引发后台CPU飙升
大事务未提交时,Undo Log不能被Purge线程回收,History list length持续增长。一旦回滚开始,Purge线程会尝试跟上清理节奏,但往往卡在“扫描undo segment → 解析log record → 标记页为可复用”这一长链路上。
- 执行
SHOW ENGINE INNODB STATUS\G,若看到PURGE PROCESSED远低于HISTORY LIST,说明Purge已滞后 - Purge线程本身占用CPU,且与回滚线程竞争Buffer Pool latch和buf_pool mutex,导致大量自旋等待
- 设置
innodb_purge_rseg_truncate_frequency = 1可临时提速,但会显著增加CPU负载(实测+15%~30%)
锁资源批量释放触发InnoDB内部状态同步
事务持有锁期间,InnoDB在内存中维护了大量锁结构(lock_sys->rec_hash、trx_lock_t等)。回滚末尾阶段要一次性释放全部锁,并通知所有等待线程,这涉及哈希表遍历、链表拆解、条件变量广播等高开销操作。
- 若该事务曾阻塞过上百个其他连接,
lock_wait_timeout超时或KILL操作会集中触发锁等待队列唤醒,CPU瞬间冲高 - State显示为
rolling back时,CPU峰值常出现在最后10%进度——那正是锁清理阶段 - 不要在回滚中途反复查
INFORMATION_SCHEMA.INNODB_TRX,每次查询都会加trx_sys->mutex,加剧CPU争用
真正危险的不是回滚花了多少CPU,而是它把整个InnoDB的并发控制机制拖进单点瓶颈:Undo重放锁住row_search_for_mysql、Purge卡住buf_pool_flush_lru、锁清理压爆lock_sys。这些模块本应并行工作,却被大事务回滚强行串行化——这才是CPU飙高的底层逻辑。











