miaodi
发布于 2025-12-05 / 7 阅读
0

MySQL Undo Log 空间异常暴涨排查记录

总结 by gemini

1. 故障背景

  • 平台环境: 腾讯云 TDSQL-C (云原生数据库)

  • 现象描述: 监控报警显示,MySQL Undo Log 空间在一周内从 300GB 异常增长至 1.3TB,导致磁盘空间占用持续上升。

  • 初步排查: 数据库中没有明显的长事务(Active Transaction),最长的活跃会话仅 5000 多秒(且为 Binlog Dump 线程),常规业务写入耗时偶有超过 1 秒。

2. 排查过程

2.1 常规嫌疑排除

首先按照标准流程排查导致 Undo Log 无法回收的常见原因:

  1. 长事务检测: 查询 information_schema.INNODB_TRX,未发现 trx_started 较早的事务。活跃事务都在 1 秒以内。

  2. Sleep 事务检测: 检查是否有程序开启事务后未提交并断开连接(僵尸会话),结果无异常。

  3. XA 事务检测: 执行 XA RECOVER,检查是否有残留的分布式事务(Prepared 状态),结果为空。

2.2 锁定核心指标

排除了“事务阻塞”后,问题指向了“清理速度跟不上生成速度”。执行 SHOW ENGINE INNODB STATUS\G 发现惊人数据:

SQL

------------
TRANSACTIONS
------------
History list length 600,812,666  <-- 积压达 6 亿

分析: 正常系统该值应在几十万级别。6 亿的积压意味着 Purge 系统已经严重滞后。

2.3 瓶颈定位

进一步分析服务器资源负载情况:

  • Purge 配置: innodb_purge_threads 已开启至最大值 32,但依然无法消化积压。

  • CPU 负载: 扩容前 CPU 使用率长期维持在 70%-90% 的高位,说明计算资源紧张,后台 Purge 线程与前台业务线程存在资源争抢。

  • 内存负载: Buffer Pool 内存占用高,且物理读(Reads/s)数值较大,表明在处理大量历史数据清理时,内存缓存不足以支撑,导致频繁回源读盘。

结论:

这是一起典型的**“小马拉大车”**案例。业务写入压力较大,叠加 6 亿的历史积压清理需求,导致原有的实例规格(CPU 计算能力和内存缓存能力)已达到瓶颈,Purge 线程无法获得足够的资源来追赶进度。

3. 解决方案

资源瓶颈明显,决定申请维护窗口进行垂直扩容。

3.1 垂直扩容

  • 规格变更: 16核 96GB $\to$ 24核 144GB

  • 目的:

    1. 增加内存: 144GB 内存提供更大的 Buffer Pool,大幅提高数据页缓存命中率,减少 Purge 过程中的物理 IO 读取耗时。

    2. 增加 CPU: 更多核心缓解了后台 Purge 线程与业务线程的资源争夺,让清理工作能全速运行。

3.2 数据库参数修改

  • innodb_purge_threads: 4 -> 8

  • innodb_purge_batch_size: 300 -> 5000

  • innodb_read_io_threads: 4 -> 12

4. 优化效果

扩容完成后,效果立竿见影:

  • Undo Log 积压缓解: History list length 立即停止增长并转为下降趋势(6.02亿 $\to$ 6.01亿 $\to$ 5.99亿),说明 Purge 速度终于超过了生成速度。

  • 资源负载降低: 在业务量不变的情况下,CPU 使用率从扩容前的 70%-90% 显著下降至 50%-60%,系统运行更加从容。

  • 吞吐量表现: 写 IOPS 小幅上升(7000 $\to$ 8000),侧面反映出 Purge 效率提升后,清理产生的脏页刷盘更加活跃。

5. 总结

对于 MySQL Undo Log 积压问题,在排除了长事务这一最常见原因后,应当重点关注 History List Length 这一关键指标。

当该指标达到亿级且持续增长时,往往意味着数据库的“消化能力”(Purge)已经落后于“进食能力”(写入)。在本案例中,通过垂直扩容(增加 CPU 和内存),用硬件资源换取了处理效率,成功化解了存储空间持续爆炸的风险。