news 2026/7/24 16:03:34

MySQL大事务的Recovery优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL大事务的Recovery优化

你有没有碰到过mysqld进程启动了很长时间也起不来的情况?这时候我们可以用perf top命令查看一下MySQL进程主要在干什么事情。如果你查看到的信息如下图所示,启动过程中MySQL的主线程(mysqld_main函数开始的线程)绝大多数的时间都花在了回滚事务上。那么很可能是遇到了大事务回滚。

这种情况最常见的一个场景是一个大事务在写Binlog时把磁盘空间占满了,导致了实例的宕机重启。我曾经遇到的最大的Binlog文件超过了114GB。由于Binlog Cache的临时文件在写完Binlog后才被清理,所以这个事务总共占用了228GB的空间。MySQL的参数binlog_error_action用来控制写Binlog文件失败的行为,默认的配置是ABORT_SERVER,就是关闭进程。用户也可以配置这个参数为IGNORE_ERROR,意思是当写Binlog失败时关闭Binlog文件,后续的事务不再产生Binlog。这种情况显然会导致主备的数据不一致,因此除非不得以不要这样设置。

根因分析

为什么在MySQL进程启动时,主线程要做事务回滚的操作呢?这源自于Binlog的Crashsafe机制,详细的原理可以参考《MySQL的CrashSafe和Binlog的关系》,这里只做一个概括的介绍。事务的DML执行时会产生Binlog Events,当事务提交时这些Binlog Events会被写入到Binlog文件并持久化。为了保证MySQL宕机重启后数据和Binlog的一致性,MySQL设计了一个Crashsafe的机制。该机制对普通事务采用了两阶段提交(2PC),也称为内部 XA(Internal XA)。

如上图所示,在内部 XA 机制下一个事务的提交过程分为三个步骤:

  1. 存储引擎Prepare事务。事务状态由ACTIVE变为PREPARED,并将事务的状态和XID持久化到Redo中。
  2. 事务会产生一个Xid_event,同DML的Binlog Events一同写入到binlog文件中,并持久化。
  3. 提交事务。

当异常宕机时,事务可能处于以下几种状态之一:

  • Active:在两阶段提交里,此类事务从未被写入 Binlog。
  • Prepared 但未写入 Binlog(或仅部分写入):事务已处于 Prepared 状态,但其 XID 未出现在 Binlog 文件中。
  • Prepared 且已写入 Binlog:事务已处于 Prepared 状态,且其 XID 已出现在 Binlog 文件中。
  • Committed:事务已经写入Binlog并且提交。

对于Committed的事务,设计上已经保证了它的Binlog Events一定写入了Binlog文件。因此Binlog和数据是一致的,启动时无需任何操作。对于Active的事务,Binlog Events肯定没有写入Binlog文件,InnoDB有一个后台回滚线程会自动将其回滚Prepared的事务则需根据最后一个Binlog 文件中的XID信息进行处理。如果该事务的XID出现在了Binlog文件中,则需要提交该事务来保证Binlog和数据的一致性;反之则回滚该事务。处理Prepared事务的过程称为Binlog Recovery必须在MySQL向用户提供服务之前完成。事务提交通常很快,但回滚往往耗时与其执行时间相当。如果一个事务执行用了1小时,回滚很可能也需要 1小时,MySQL在此期间将不可用。

为什么必须要在提供服务前回滚所有事务呢?这和XID的实现有关系。XID是用MySQL前缀加上query_id构成的,query_id是一个全局的计数器,系统重启后会重新从1开始计数。如果在启动后,不对之前的Prepared事务进行提交或者回滚,那么就可能出现两个Prepared的事务有相同XID的情况。在恢复时,就无法区分哪个事务该提交,哪个事务该回滚。

异步回滚Prepared事务

在AliSQL中,我们设计了一套异步回滚的机制来解决这个问题。

如上图所示,这个设计中将Prepared的事务回滚分为两个部分:

  1. 主线程将事务状态设为Active并持久化该状态。
  2. 利用InnoDB的后台回滚线程异步回滚事务的所有操作。

Binlog Recovery在完成第一部分后即可立即对外提供服务。由于第一步的执行非常快,Binlog Recovery可以在很短的时间内完成。

在宕机重启时,Active的事务会被InnoDB通过后台线程直接回滚掉,不需要XID来辅助决策。所以恢复时,只要将要回滚的事务的状态从Prepared改成Active就能避免两个Prepared事务有相同XID的问题。这里关键是要对Active的状态做持久化,保证在宕机重启后事务的状态仍然是Active,这样InnoDB就会自动将这个事务回滚掉。

社区版的InnoDB原本对Prepared事务的回滚就是先设置成Active状态,然后再根据Undo记录进行回滚。Active的状态会记录到Redo中,只是没有对Redo做持久化。然而InnoDB默认每秒会做一次Redo的持久化,所以在改成Active后,很快就会被持久化。因此当碰到了大事务回滚造成实例无法启动的情况时,即使是在社区版本,我们只要强制重启MySQL进程,大事务就会转变成后台回滚,不再阻塞实例的启动

这个功能的源码贡献给了MariaDB,已经合并到MariaDB-11.7中,详情参考MDEV-33853[1]。

结论

通过异步回滚的设计,在Binlog Recovery阶段只需要将Prepared的事务的状态设置为Active,真正耗时的事务回滚则由InnoDB的后台回滚线程异步的执行。通过这个优化,原本需要几十分钟甚至几个小时的启动过程,被缩短到秒级完成。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/22 4:59:21

DNS 劫持实操:黑客技术真的没有你想象的那么难!

黑客技术?没你想象的那么难!——dns劫持篇 什么是DNS劫持? DNS劫持就是通过劫持了DNS服务器,通过某些手段取得某域名的解析记录控制权,进而修改此域名的解析结果,导致对该域名的访问由原IP地址转入到修改后…

作者头像 李华
网站建设 2026/7/22 3:21:03

收藏必备!情境工程:大模型时代企业知识管理系统的革命性变革

文章探讨了情境工程如何重塑企业知识管理系统,从传统"文档存储检索"模式转变为"主动赋能"。通过场景感知、动态连接和人机协同进化,构建企业"智能认知中枢",实现决策质量跃升、组织能力沉淀和创新加速。系统五…

作者头像 李华
网站建设 2026/7/22 3:21:03

电商源码系统集成海量促销功能,引爆销售增长

温馨提示:文末有资源获取方式在竞争激烈的电商市场,强大的营销能力是脱颖而出的核心。我们介绍一款集成了多种促销工具的电商源码系统,它专为提升销售和用户互动而设计,直接可用于商业运营,助您轻松实现业绩突破。以下…

作者头像 李华
网站建设 2026/7/22 5:19:03

当然这个表格不是我整理的,数据来源于网络,大家仅供参考,拿出来跟大家分享的目的也是跟大家一起交流讨论一下,毕竟每个人的背景和经历都不太一样,对于“难”字的定义肯定也有着不同的维度,大家也可以说出你心1

当然这个表格不是我整理的,数据来源于网络,大家仅供参考,拿出来跟大家分享的目的也是跟大家一起交流讨论一下,毕竟每个人的背景和经历都不太一样,对于“难”字的定义肯定也有着不同的维度,大家也可以说出你…

作者头像 李华
网站建设 2026/7/22 2:04:04

django-flask基于python的城市宠物医院管理系统的设计与实现

目录摘要关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!摘要 随着城市化进程加快和宠物饲养率上升,宠物医疗需求显著增长。基于Python的Django-Flask框架设计的城市宠物…

作者头像 李华