【MySQL】redo log

本文深入解析InnoDB存储引擎的redolog,包括刷盘策略、日志文件组设计,以及为何使用redolog而非直接刷数据页。重点讲解了其优势和背后的原理,让读者理解崩溃恢复过程。
  1. 简介
      redo log 它是物理日志,记录内容是“在某个数据页上做了什么修改”,属于 InnoDB 存储引擎。redo log(重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。 比如 MySQL 实例挂了或宕机了,重启时,InnoDB存储引擎会使用redo log恢复数据,保证数据的持久性与完整性。
  2. 刷盘策略
      InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数,它支持三种策略:
    ① 0 :设置为 0 的时候,表示每次事务提交时不进行刷盘操作。
    ② 1 :设置为 1 的时候,表示每次事务提交时都将进行刷盘操作(默认值)。
    ③ 2 :设置为 2 的时候,表示每次事务提交时都只把 redo log buffer 内容写入 page cache。
      innodb_flush_log_at_trx_commit 参数默认为 1 ,也就是说当事务提交时会调用 fsync 对 redo log 进行刷盘 另外,InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用 fsync 刷盘。除了后台线程每秒1次的轮询操作,还有一种情况,当 redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。
  3. 日志文件组
      硬盘上存储的 redo log 日志文件不只一个,而是以一个日志文件组的形式出现的,每个的redo日志文件大小都是一样的。 比如可以配置为一组4个文件,每个文件的大小是 1GB,整个 redo log 日志文件组可以记录4G的内容。 它采用的是环形数组形式,从头开始写,写到末尾又回到头循环写,如下图所示。

  在个日志文件组中还有两个重要的属性,分别是 write pos、checkpoint。write pos 是当前记录的位置,每次刷盘 redo log 记录到日志文件组中,write pos 位置就会后移更新。checkpoint 是当前要擦除的位置,每次 MySQL 加载日志文件组恢复数据时,会清空加载过的 redo log 记录,并把 checkpoint 后移更新。write pos 和 checkpoint 之间的还空着的部分可以用来写入新的 redo log 记录。
  如下图所示,以顺时针为正方向,在write pos正方向和checkpoint负方向之间的部分可以用来写入新的 redo log 记录。

  如果 write pos 追上 checkpoint ,表示日志文件组满了,这时候不能再写入新的 redo log 记录,MySQL 得停下来,清空一些记录,把 checkpoint 推进一下。

  1. redo log的优势
      现在我们来思考一个问题: 只要每次把修改后的数据页直接刷盘不就好了,还有 redo log 什么事?它们不都是刷盘么?差别在哪里?
      实际上,数据页大小是16KB,刷盘比较耗时,可能就修改了数据页里的几 Byte 数据,有必要把完整的数据页刷盘吗? 而且数据页刷盘是随机写,因为一个数据页对应的位置可能在硬盘文件的随机位置,所以性能是很差。 如果是写 redo log,一行记录可能就占几十 Byte,只包含表空间号、数据页号、磁盘文件偏移量、更新值,再加上是顺序写,所以刷盘速度很快。 所以用 redo log 形式记录修改内容,性能会远远超过刷数据页的方式,这也让数据库的并发能力更强。
### MySQL Redo Log 写入过程及工作机制 #### 1. **Redo Log 的定义** MySQL 的 `redo log` 是 InnoDB 存储引擎中的一个重要组件,主要用于实现 Write-Ahead Logging (WAL) 技术。其核心目的是在数据库发生崩溃时能够快速恢复未完成的事务数据[^3]。 #### 2. **Redo Log 的写入流程** 当 MySQL 更新一条记录时,具体的过程如下: - 数据页被加载到内存缓冲池中,并在此基础上修改。 - 修改完成后,在内存中生成对应的 `redo log` 记录,这些记录暂时存储在 `redo log buffer` 中[^5]。 - 随后,根据配置参数 `innodb_flush_log_at_trx_commit` 的设置决定如何处理 `redo log`: - 如果该参数值为 0,则仅将 `redo log` 缓存在内存中,不立即同步至磁盘[^5]。 - 若值为 1(默认),则每次事务提交都会通过 `fsync` 将日志持久化到磁盘[^5]。 - 当值设为 2 时,虽然也会调用 `write` 方法将日志写入操作系统缓存区 (`page cache`),但不会立刻触发 `fsync` 操作[^5]。 #### 3. **Redo Log 的刷盘机制** 除了基于事务级别的控制外,还有其他几种情况会促使 `redo log` 进行刷盘操作: - 定期自动刷新:无论是否有新的事务到来,InnoDB 都会在每秒定时执行一次 `fsync` 来确保部分已产生的日志能及时落地。 - 缓冲区容量限制:一旦发现当前使用的 `redo log buffer` 已经接近预设大小的一半(`innodb_log_buffer_size`),系统便会提前启动刷盘程序以腾出更多空间继续记录新事件[^5]。 #### 4. **组提交优化(Group Commit Optimization)** 为了提高效率减少频繁 I/O 开销,MySQL 实现了一种称为“组提交”的策略。即多个并发运行的小型独立事务可以在同一时刻共享同一批次的数据写出机会。例如在一个较大的事务尚未完全结束之前如果有其它小型事务请求加入队列等待提交的话,那么它们可能会搭便车一同参与最终的大规模物理层面上的实际硬盘写入动作从而节省资源消耗[^2]。 ```python # 示例代码展示如何调整 innodb_flush_log_at_trx_commit 参数 SET GLOBAL innodb_flush_log_at_trx_commit = 1; ``` --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值