Mysql系列-Redo log日志

本文深入探讨Mysql的Redolog机制,包括其作用、结构、持久化方式及组提交优化,解析Redolog在事务持久化和数据库恢复中的关键角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mysql系列–事务日志中,我们介绍了Mysql中的事务日志,这里主要介绍Mysql事务日志中的Redo log日志。

Redo log是什么?

Redo log是重做日志,提供前滚操作。Redo log是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成什么样的。Redo log用来恢复提交后的物理数据页,但只能恢复到最近一次提交的内容。

Redo log包括两部分:内存中的日志缓存(log buffer)和磁盘上的日志文件(log file),其中日志缓存是易失的,日志文件是持久化的。

在Innodb存储引擎中,Redo log是以块为单位进行存储的,称为Redo log block,每个块占512字节,因此log buffer(内存日志)、os buffer(文件系统缓存)以及redo log file on disk(日志文件)都是以512字节的块存储的。

Redo log block由三部分组成:日志块头(12)+日志数据(492)+日志块尾(8),当数据页的修改较多需要超过492字节的日志记录时,就会使用多个Redo log block来记录数据页的修改。

Redo log是以顺序的方式追加到文件尾,并且Redo log的文件大小(由innodb_log_file_size指定)是固定的,当文件满时必须要先刷盘才能继续写,这会影响Mysql的性能。为了解决这个问题,引入了Redo log group的概念,即group中存在多个Redo log文件,每次只使用其中一个Redo log文件,当写满了就切到另一个Redo log文件,并触发Redo log的刷盘。group中Redo log文件的个数由参数innodb_log_files_group控制,默认为2。

需要注意,group只是一个逻辑概念,并没有真实文件目录来表示该group,Redo log的存储位置是由参数innodb_log_group_home_dir指定的,默认在datadir下。
Redo log文件大小对性能影响较大,当文件大小较大时,通过Redo log恢复时间就较长,当文件大小较小时,会导致频繁切换Redo log。

Redo log持久化

在概念上,Innodb通过force log at commit机制实现事务的持久化,即在事务提交的时候,必须先将该事务的所有事务日志写入到redo log file和undo log file中进行持久化。在事务持久化的过程中,通过DoubleWrite技术来保证Redo log正确的持久化。

为了提升事务提交性能,Redo log一般都是先写入log buffer中,在后续合适时机将log buffer写入到log file中进行持久化,即刷盘。由于log buffer中的数据是存在内存中,是易失的,为了尽可能减少事务提交后数据丢失的影响,可以通过innodb_flush_log_at_trx_commit 控制redo log的刷盘,取值0、1、2:

  • 0 : 提交事务的时候,不立即把 redo log buffer 里的数据刷入磁盘文件的,而是依靠 InnoDB 的主线程每秒执行一次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,然后此时内存里的数据全部丢失。
  • 1 : 提交事务的时候,就必须把 redo log 从内存刷入到磁盘文件里去,只要事务提交成功,那么 redo log 就必然在磁盘里了。注意,因为操作系统的“延迟写”特性,此时的刷入只是写到了操作系统的缓冲区中,因此执行同步操作才能保证一定持久化到了硬盘中。
  • 2 : 提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件,可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。

除此之外,还存在以下场景触发日志刷盘动作:

  • 定时刷盘(默认1s一次),这个刷日志频率由innodb_flush_log_at_timeout控制。
  • Log buffer中已使用内存超过一半
  • 当有checkpoint时,checkpoint是指检查点,可以加快Mysql的重启恢复过程,在重启恢复过程中,只需要恢复checkpoint之后的日志。c heckpoint在一定程度上可以代表已刷盘的日志位置。

Redo log组提交

当innodb_flush_log_at_trx_commit=1时,在事务每次commit时,仍然需要有一次日志刷盘操作,这个操作将会成为事务并发的瓶颈。为了解决这个问题,Mysql提出了Redo log组提交,即将同时提交的事务一次刷盘,注意这里不是等待一段时间后批量刷盘,而是将同时提交的事务一次性刷盘。

实现Redo log组提交需要依赖LSN(Log Sequence Number),LSN是单调递增的,当多个事务同时提交时,按照以下流程执行:

  1. 获取log_mutex
  2. 若flushed_to_disk_lsn >= lsn,表示日志已经被刷盘,跳转5
  3. 若current_flush_lsn >= lsn,表示日志正在被刷盘,跳转5后进入等待状态
  4. 将小于lsn的日志刷盘(组提交)
  5. 释放log_mutex

在第4步中,在刷盘的过程中,顺便把较小的lsn对应的事务一起刷盘。

LSN不仅可用于Redo log组提交,还可以用于checkpoint。LSN占用8字节,包含以下信息:数据页的版本信息、写入的日志总量,通过LSN开始号码和结束号码计算和检查点的位置

LSN不仅存在于redo log中,还存在于数据页中,在每个数据页的头部,有一个fil_page_lsn记录了当前页最终的LSN值是多少。由于redo log和数据同时存在于内存和磁盘中,内存和磁盘间的数据存在一定的延迟,因此会有4个LSN。

可以通过show engine innodb status查看当前lsn相关信息。
在这里插入图片描述

在进行数据恢复过程中,通过数据页中的LSN值和redo log中的LSN值比较,如果数据页中的LSN值小于redo log中LSN值,则表示数据丢失了一部分,这时候可以通过redo log的记录来恢复到redo log中记录的LSN值时的状态。

数据刷盘时机-checkpoint

上文介绍了Redo log的刷盘,而数据也是以数据页的形式存在内存中,也是需要将其刷盘的。触发数据刷盘的规则只有一个:checkpoint,但触发checkpoint的场景有多个。当checkpoing触发后,将会把脏数据页和脏日志页都刷到磁盘中。
checkpoint目的有:

  • 缩短数据库的恢复时间
  • 数据页(buffer pool)不够用时,将数据脏页刷到磁盘
  • redo log不可用时,将日志脏页刷到磁盘

checkpoint分为两类:

  • sharp checkpoint:完全检查点,数据库正常关闭时,会触发将所有脏页(日志和数据)写回磁盘。在数据库正常运行过程中,不会触发sharp checkpoint。
  • fuzzy checkpoint:模糊检查点,当满足一定的条件部分刷盘,一次只刷一部分,避免全局刷盘造成Mysql系统的卡顿。在数据库正常运行期间发生,存在4种情况触发该检查点。

触发fuzzy checkpoint的场景:

  • master thread checkpoint:异步以每秒或10秒从缓冲池的脏页列表中刷一定比例页到磁盘中。可以通过innodb_io_capacity控制刷脏页数。
  • flush_lru_list checkpoint: Mysql需要保证有足够可用的空闲页,当不足时从lru列表中移除足够的页,当这些页有脏页时,就会触发checkpoint。在5.6以后的版本,由page cleaner线程负责保证有足够的可用空闲页。通过innodb_lru_scan_depth可以控制可用页的数量。
  • async/sync flush checkpoint:log file快满时,会批量触发数据页的回写,根据log file不可被覆盖的比例可分为同步刷盘和异步刷盘,当达到75%,则触发异步刷盘,当达到90%,则触发同步刷盘。在5.6以后的版本,由page cleaner线程负责保证有足够可用的log file。
  • dirty page too much checkpoint:脏页太多检查点,为了保证buffer pool的空间可用性。脏页的比例由参数innodb_max_dirty_pages_pct控制。

更多精彩,请关注
在这里插入图片描述

### MySQL Redo Log 的工作原理及用途 #### 作用 MySQL 中的 Redo Log 是 InnoDB 存储引擎中的核心组件之一,主要用于保障数据库事务的一致性和持久性。当数据库发生崩溃时,Redo Log 能够帮助恢复未完成的数据写入操作,从而确保事务不会因为意外中断而丢失[^2]。 具体来说,Redo Log 记录了所有对数据页所做的修改操作。这些记录可以用来重新执行(即重做)那些已经提交但尚未完全写入磁盘的操作。通过这种方式,即使系统在某个时间点突然宕机,重启后也能利用 Redo Log 将数据恢复到最新的状态[^1]。 --- #### 结构 Redo Log 的存储结构由两部分组成:**Log Buffer** 和 **Log File**。 1. **Log Buffer**: 这是一个位于内存中的缓冲区,在服务器启动时会预先分配一片连续的空间作为 redo log buffer。所有的日志写入操作都会优先写入这个缓冲区中,而不是直接写入磁盘上的文件。这样做的目的是为了减少频繁的随机 IO 操作,提升性能[^4]。 2. **Log File**: 当 Log Buffer 达到一定条件(例如满了或者满足特定的时间间隔),其内容会被刷入磁盘上的物理文件中。这部分文件通常被称为 redo log file 或者 ib_logfile* 文件。它们保存着实际的日志数据,并且具有循环覆盖的特点——也就是说,旧的日志会在不再需要的时候被新日志替换掉。 此外,还存在一个重要的参数 `innodb_flush_log_at_trx_commit`,它可以控制何时将 Log Buffer 刷入磁盘- 如果设置为 0,则每秒刷新一次; - 设置为 1 表示每次事务提交都立即同步到磁盘- 设置为 2 同样也是按需写回缓存,不过仅保证一秒内至少有一次真正的 fsync() 操作。 --- #### 配置方法 以下是几个常用的配置项及其含义: 1. **innodb_log_file_size** - 定义单个 redo log 文件的最大尺寸,默认情况下可能不足以应对高负载环境下的需求。 - 修改此值需要注意停服重建表空间的过程可能会比较耗时。 2. **innodb_log_files_in_group** - 控制一组中有多少个 redo log files 可供轮转使用。 3. **innodb_log_buffer_size** - 如前所述,这是指定了 Log Buffer 大小的一个变量,默认值一般设得较小(如 16 MB)。对于大事务场景下建议适当调增以降低磁盘压力。 4. **sync_binlog** - Binlog 的同步频率虽然不直接影响 Redo Log,但如果两者配合不当也可能引发一致性问题,因此也需要关注它的取值范围。 --- ```sql -- 查看当前 redo log 参数配置 SHOW VARIABLES LIKE 'innodb%log%'; SET GLOBAL innodb_flush_log_at_trx_commit = 1; -- 动态调整trx commit行为 ``` 上述 SQL 查询语句可以帮助管理员快速获取关于 redo log 的现有设定情况并作出相应优化决策。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuzhiyuxia

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值