问题来源
📚 全文字数 : 2k
⏳ 阅读时长 : 5min
📢 关键词 : redolog、事务未提交、持久化
今天的文章内容围绕一位网友的评论去展开,他提出了这么一个问题,如下:
换个方式提取出他想问的:可以理解为如果在redolog持久化过程中,意外情况导致事务未提交,那是不是redolog就写入不了磁盘了?
本期内容就从这个问题进行展开要讲的内容
我们知道持久化的目的是可以在数据丢失后进行恢复,保证数据不丢失,对于MySQL来说只要 binlog 和 redolog 都能正确持久化到磁盘上,就可以保证数据不丢失了。
👉 那意外情况导致事务还没提交的时候,redolog 能不能被持久化到磁盘呢?
先公布答案,确实会有这种情况
为什么会有这种可能呢,难道是被动刷盘了?先不着急想象,我们接着往下看,这个问题今天必须拿下!
redo log可能存在的位置
没看过看头提到的文章建议返回去看下,这里再进行下核心知识点的回忆。
redo log 其实记录的是此次事务「完成后」的数据状态,记录的是更新之后的值。
我们来回顾看下redolog的写入流程:
- 修改操作时先将原始数据从磁盘中读入内存中来,修改数据,如图中的脏页
- 此时产生日志吸入redo logbuffer,记录的是数据被修改后的值
- 当事务commit时,将redo logbuffer中的内容采用追加方式刷新到redo logfile
- 调用fsync将修改的数据刷新到磁盘中
也就是说redolog可能存在于三种位置状态:
redolog buffer:
写入redo log buffer就用到了的WAL(Write-Ahead Logging)技术,日志先写入redo log buffer缓冲区
page cache:
page cache是文件系统缓冲,如果是写到磁盘,但是没有持久化(fsync),物理上是在文件系统的page cache里面
硬盘disk:
从page cache 持久化到磁盘,也就是磁盘中的redo log file中,你在data目录中看到的ib_logfile文件就是实际的redo log日志文件,它文件组的形式出现的。这些文件以ib_logfile[数字](数字可以是0、1、2..)的形式进行命名。
事务提交的过程
一般来说事务的提交也应该有以下三个过程:
写磁盘策略
缓存在 redo log buffer 里的 redo log 是在内存中的,最终是要刷到磁盘中。
👉 那么redo log是如何被控制写入刷入磁盘的呢?
这就涉及到redo log的刷盘策略了
InnoDB通过innodb_flush_log_at_trx_commit 参数可以控制策略,该参数控制 commit 提交事务时,如何将 redo log buffer中的日志刷新到 redo log file 中,它支持设定0,1, 2也就是说支持三种策略设置。
这个策略我们可以用参数设置:
show variables like 'innodb_flush_log_at_trx_commit'
//默认情况下 innodb_flush_log_at_trx_commit值是1
InnoDB存储引擎有一个后台线程,每隔1秒,就会把 redo log buffer 中的内容写到文件系统缓存(Page Cache),然后调用fsync进行刷入到磁盘的操作。
延迟写
设置为0(延迟写) :每次事务提交时不主动进行刷盘操作,redo log依然留在redo log buffer中,然后后台进程每秒写入page cache中,然后持久化到磁盘中。
实时写,实时刷
设置为1 (实时写,实时刷):每次事务提交时都会直接将缓存在redo log buffer中的redo log直接持久化到磁盘中( 默认值 )。
实时写,延时刷
设置为2(实时写,延时刷) :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步,由os自己决定什么时候同步到磁盘文件。
事务未提交写磁盘的情况
看了redo log可能存在的状态和位置,以及写盘策略,那跟事务是否提交redo log能否写入磁盘有啥关系呢?
那我们看下面几种情况是不是在事务没提交的时候也可能会写入到磁盘呢?
后台线程每隔1s刷新
上面我们说到InnoDB 有一个后台线程,每隔 1 秒轮询一次,具体的操作是这样的:调用 write 将 redolog buffer 中的日志写到文件系统的 page cache,然后调用 fsync 持久化到磁盘。
那么写入到redolog buffer中的redo log在事务没提交的时候,可能就会后台线程在持久化的时候被一起持久化到磁盘中。
其他事务提交成功
我们在设置写盘策略的时候 innodb_flush_log_at_trx_commit 设置为1时,在每次事务提交的时候都会直接将缓存在redo log buffer中的redo log直接持久化到磁盘中。
举个栗子,事务 A 执行到一半,此时 redolog 到 redolog buffer 中,这时候有另外一个事务 B 提交,事务 B 要把 redolog buffer 里的日志全部持久化到磁盘,这时候就会带上是不是事务 A 在 redolog buffer 里的日志一起持久化到磁盘。
(⊙o⊙)…
redo log buffer 空间快满了
另一种说法是当redo log buffer 占用的空间达到 redolog buffer 大小一半的时候,后台线程会主动写盘。
redo log buffer 占用空间由参数 innodb_log_buffer_size 控制,默认是 8MB
但是这个写盘动作只是 write 到了文件系统的 page cache,仍然是在内存中,并没有调用 fsync 真正落盘
🔔朋友们下次当面试官问你:事务还没提交的时候,redo log 能不能被持久化到磁盘呢?
你应该知道如何回答了吧,哈哈,拿下。