MySQL中的预写日志机制

在 MySQL 中,InnoDB 存储引擎实现了 WAL 机制。

包含 Redo log buffer、Redo log、Undo Log 等,来记录事务已提交但未写入数据文件的数据变更以及事务回滚后的数据还原。

为了给大家讲清楚 MySQL 的预写日志机制,会涉及到 MySQL 架构中的以下内容

图片[1]-MySQL中的预写日志机制-不念博客

Buffer Pool(缓冲池)

Buffer Pool (缓冲池)是 InnoDB 存储引擎中非常重要的内存结构,顾名思义,缓冲池就是起到一个缓存的作用,因为我们都知道 MySQL 的数据最终是存储在磁盘中的,如果没有这个 Buffer Pool 那么我们每次的数据库请求都会磁盘中查找,这样必然会存在 IO 操作,这肯定是无法接受的。

但是有了 Buffer Pool 就是我们第一次在查询的时候会将查询的结果存到 Buffer Pool 中,这样后面再有请求的时候就会先从缓冲池中去查询,如果没有再去磁盘中查找,然后在放到 Buffer Pool 中。

Redo log buffer(日志缓冲区)

Redo log buffer 是用作数据变更记录写入 Redo log 文件前的一块内存区域。日志缓冲区大小由 innodb_log_buffer_size 变量定义,默认大小为 16MB。

日志缓冲区的内容会定期刷新到 Redo log 文件中,大型日志缓冲区允许大型事务运行,而无需在事务提交之前将 Redo log 数据写入磁盘。因此如果事务涉及的更新、插入或删除操作数据量较大时,可以增加日志缓冲区的大小可以节省磁盘 I/O。

MySQL 提交事务的时候,会将 Redo log buffer 中的数据写入到 Redo log 文件中,刷磁盘可以通过 innodb_flush_log_at_trx_commit 参数来设置

  • 值为 0 表示不刷入磁盘
  • 值为 1 表示立即刷入磁盘
  • 值为 2 表示先刷到 os cache

为了提高性能,MySQL 首先将修改操作写入到日志缓冲区,之后以 innodb_flush_log_at_trx_commit 参数设置落盘时机,将日志缓冲区刷入到磁盘的 Redo log 文件中去。

Redo Log

MySQL Redo Log 是 InnoDB 存储引擎中的一个重要组件,它是一种磁盘基础的数据结构,用于在崩溃重启期间修复由已提交事务但未写入数据文件的数据。

在正常操作中,Redo log 记录了由 SQL 语句执行导致的表数据变更记录。将 Redo log buffer 中的数据持久化到磁盘中,就是将 Redo log buffer 中的数据写入到 Redo log 磁盘文件中。

数据在由 Redo log buffer 写入 Redo log 时的触发时机如下,

  • MySQL 正常关闭时触发
  • 当 Redo log buffer 中记录的写入量大于 Redo log buffer 内存空间的一半时,会触发落盘
  • InnoDB 的后台线程每隔 1 秒,将 Redo log buffer 持久化到磁盘
  • 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘(这个策略就是由上文提高 innodb_flush_log_at_trx_commit 参数控制)

Redo log 是 WAL 机制的核心,它记录了事务所做的所有修改。如果数据库发生故障,可以使用 Redo 日志来重做事务,从而确保数据的一致性。

Undo Log

Undo Log 记录了如何撤销一个事务的修改。如果需要回滚事务或在执行事务时还未提交,数据库就发生了崩溃,这时我们就需要将未提交事务前的数据回滚回去,难道这个操作有我们自己来做吗?显然 MySQL 也考虑到了这一点。

MySQL 会使用 Undo log 来撤销未提交的修改。在操作数据前,MySQL 首先将数据备份到 Undo log,然后进行数据修改。

如果出现错误或者用户执行了 Rollback 语句,系统可以利用 Undo log 中的备份将数据恢复到事务操作前的状态。

通过 Undo log 撤销修改,从而确保数据的原子性。

结合 Buffer Pool、Redo log buffer、Redo log、Undo log 后,我们在MySQL 中更新一条数据的流程如下

图片[2]-MySQL中的预写日志机制-不念博客
  • 准备更新一条 SQL 语句
  • MySQL(innodb)会先去缓冲池(Buffer Pool)中去查找这条数据,没找到就会去磁盘中查找,如果查找到就会将这条数据加载到缓冲池(Buffer Pool)中
  • 在加载到 Buffer Pool 的同时,会将这条数据的原始记录保存到 undo 日志文件中
  • innodb 会在 Buffer Pool 中执行更新操作
  • 更新后的数据会记录在 Redo log buffer 中
  • MySQL 提交事务的时候,会将 Redo log buffer 中的数据写入到 Redo log 文件中,刷磁盘可以通过 innodb_flush_log_at_trx_commit 参数来设置
  • MySQL 重启的时候会将 Redo log 恢复到缓冲池中
© 版权声明
THE END