写点什么

关于事务、redolog 写入的两个问题分析

发布于: 2021 年 01 月 14 日
关于事务、redolog 写入的两个问题分析

一 背景

某个讨论群内,有朋友提出这样两个问题:


转文字:

1、那就是如果未提交的时候,redolog 写满了,此时是阻塞还是覆盖呢

2、如果未提交然后写满了此时落盘了,你磁盘不是有脏数据了么,这二个问题不明白

关于问题大家在群内做了简单讨论,我再翻阅资料确认一些细节后,得到的分析结果如下。老规矩,先分析、分解问题,【先问是不是,再问为什么】,然后再去寻找、确定答案。

二 问题 1

首先,分析了一下问题 1 的描述:

【未提交】指的是当前存在一个未提交的事务,【redolog 写满了】指此时 redolog 文件此时是写满的状态,所以最终我们的问题是:

1-1 这个未提交事务是否会写 redolog

1-2 如果要写 redolog,是立即覆盖写入,还是需要阻塞一段时间,然后再写入。



1-1 未提交事务是否会写 redolog

涉及事务提交流程和 redolog 的写入机制:

有 binlog 情况下,commit 动作开始时,会有一个 Redo XID 的动作记录写到 redo,然后写 data 到 binlog,binlog 写成功后,会将 binlog 的 filename,日志写的位置 position 再写到 redo(position 也会写到 pos 文件里),此时才表示该事务完成(committed)。如果只有 XID,没有后面的 filename 和 position,则表示事务为 prepare 状态。

所以,未提交事务修改的数据并不会写 redolog。



事务提交流程:

      commit; --> write XID to redo. --> write data to Binlog. --> write filename,postsion of binlog to redo. --> commited.

  记录 Binlog 是在 InnoDB 引擎 Prepare(即 Redo Log 写入磁盘)之后,这点至关重要。

 


crash 发生在不同阶段时的事务状态和事务结果:


总结起来说就是如果一个事务在 prepare 阶段中落盘成功,并在 MySQL Server 层中的 binlog 也写入成功,那这个事务必定 commit 成功。但二者缺一不可。

1-2 事务提交且当 redolog 文件满时,是否可以立即覆盖写入

如果确定需要写 redo log 文件,这时要看 checkpoint。redo log 文件是循环写入的,覆盖写之前,总要保证对应的(即将被覆盖的)脏页已经刷到了磁盘。所以如果要覆盖的脏页已经被刷到磁盘,那么久直接覆盖;如果还没刷到磁盘,就需要阻塞等待脏页完成刷到磁盘后再执行覆盖。



二 问题 2

在事务提交之前,重做日志写入了 redolog 文件;但事务回滚了,那么后续是怎么处理的?

通过问题 1 的分析,可以得出结论,问题 2 中:【在事务提交之前,重做日志写入了 redolog 文件】是不存在的。至于事务回滚,是利用 undo log 来恢复/还原数据,当用户在 commit 之后通过 rollback 执行回滚时,或异常失败时,undo 日志讲数据库“逻辑地”恢复到原来的样子(所有的修改都被逻辑取消,但数据结构和页本身在回滚之后可能大不相同)。我们将在后续文章中进行详细分析,事务的提交和回滚过程。

三 相关资料

借此问题,再回顾一下 redolog 的概念和写入机制(资料来自《MySQL 技术内幕 InnoDB 存储引擎 第 2 版》):

事务的执行过程中,生成的 redo log 先写 redo log buffer,后根据需要落磁盘(redo log 文件);

redo log 三种状态:

  • 存在 redo log buffer 中,物理上是在 MySQL 进程内存中

  • 写到磁盘(write),但是没有持久化(fsync),物理上是在文件系统的 page cache 里

  • 持久化磁盘,对应的是 hard disk

日志写到 redo log buffer 是很快的,write 到 page cache 也差不多,但是持久化到磁盘的速度就慢多了。

InnoDB 提供了 innodb_flush_log_at_trx_commit 参数,取值如下:

  1. 设置为 0 时,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中;

  2. 设置为 1 时,表示每次事务提交时都将 redo log 直接持久化到磁盘;

  3. 设置为 2 时,表示每次事务提交时都只是把 redo log 写到 page cache。

InnoDB 有一个后台线程,每隔 1 秒,就会把 redo log buffer 中的日志,调用 write 写到文件系统的 page cache,然后调用 fsync 持久化到磁盘。



更详细的相关资料可参考:

MySQL的WAL(Write-Ahead Logging)机制

MySQL · 引擎特性 · InnoDB redo log漫游

MySQL事务提交流程



发布于: 2021 年 01 月 14 日阅读数: 34
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
关于事务、redolog 写入的两个问题分析