Dawn's Blogs

分享技术 记录成长

0%

MySQL高级 (9) 事务日志

事务的隔离性机制实现。

而事务的原子性、一致性和持久性由事物的redo日志undo日志来保证。

  • redo日志(重做日志):提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性(如在内存中修改还没来得及写入磁盘中,此时系统宕机,就需要redo日志来保证修改写入到磁盘中)
  • undo日志(回滚日志):回滚行记录到某个特定版本,用来保证事务的原子性、一致性

undo日志不是redo日志的逆过程,redo和undo都可以是看作是恢复操作

  • redo日志:是存储引擎层生成的日志,记录的是物理级别上的页修改操作,主要为了保证数据的可靠性
  • undo日志:是存储引擎层生成的日志,记录的是逻辑操作日志,如对某个表进行了INSERT操作,那么undo日志就记录一条与之相反的DELETE操作。主要用于回滚一致性非锁定读

redo日志

InnoDB是以为单位来管理存储空间的。在访问页面时,需要先把磁盘上的页缓存到内存中的缓冲池中,所有的修改必须先更新缓冲池中的数据,然后缓冲区中的脏页(写入缓冲池但还没有写回磁盘的页)以一定频率被刷新到磁盘中。

为什么需要redo日志

若有这样一种场景,当事务提交后,刚写完缓冲池还没来得及将修改写回磁盘,数据库宕机了,那么这段数据就丢失了。

但是,事务包含了持久性的特点,对于一个已经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库中所做的更改也不能丢失。

所以,这就引入了redo日志:只需要把修改了哪些东西记录一下就好。InnoDB的事务采用了WAL(Write-Ahead Logging)技术,这种技术的思想就是先写日志(redo日志),再写磁盘,只有日志成功写入,事务才算提交成功。当服务器宕机还未刷新磁盘时,可以通过redo日志恢复,以保证事务的持久性

redo日志的作用

redo日志概述

采用redo日志的好处

  • 降低了刷盘频率
  • 占用的空间很小:只需要记录表空间ID,页号,偏移量以及需要更新的值,占用空间小刷盘快

redo日志的特点

  • redo日志是顺序写入磁盘的:使用顺序IO,效率高
  • 事务执行过程中,redo日志不断记录

redo日志的组成

  • **重做日志的缓冲 (redo log buffer)**:保存在内存中,是易失的
  • 重做日志文件 (redo log file) :保存在磁盘中,是持久的

redo的流程

  1. 先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
  2. 生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
  3. 当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式
  4. 定期将内存中修改的数据刷新到磁盘中

redo流程

redo日志的刷盘策略

redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以一定的频率刷入到真正的redo log file 中。这里需要讨论redo日志的刷盘策略,以保证redo log buffer中的内容被正确的写入到磁盘中的redo日志中。

还要注意的是,redo log buffer刷盘到redo log file的过程并不是真正的刷到磁盘中去,只是刷入到文件系统缓存(page cache)中去,真正的写入会交给系统自己来决定(比如page cache足够大了)。那么对于InnoDB来说就存在一个问题,如果交给系统来同步,同样如果系统宕机,那么数据也丢失了(虽然整个系统宕机的概率还是比较小的)。

针对这种情况,InnoDB给出innodb_flush_log_at_trx_commit参数,该参数控制提交事务时,如何将 redo log buffer 中的日志刷新到 redo log file 中,它支持三种策略:

  • 设置为0:表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次redo日志的同步)
  • 设置为1:表示每次事务提交时都将进行同步,刷盘操作(默认值
  • 设置为2:表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由操作系统自己决定什么时候同步到磁盘文件。

undo日志

undo日志保证事务的原子性。在事务中更新数据的前置操作其实是写入undo日志。

undo日志的必要性

事务需要保证原子性,即事务中的操作要么全部完成,要么什么都不做。当事务执行的过程中出现了错误,需要回滚时,就需要undo日志:把事务过程中对记录的改动(插入、删除、修改)记录下来,以便进行回滚操作。

此外,undo日志会产生redo日志,undo日志的产生也会伴随着redo日志的产生,因为undo日志也需要持久性的保护。

InnoDB对undo log的管理采用段的方式,也就是回滚段(rollback segment)。每个回滚段记录了1024 个undo log segment,而在每个undo log segment段中进行 undo页 的申请。

  • 在InnoDB1.1之前,只有一个回滚段,因此支持同时在线的事务限制为1024
  • 从InnoDB1.1开始,支持最大128个回滚段,故其支持同时在线的事务限制提高到了128 * 1024

总结

在一次事务中进行异常数据更新时,进行一下步骤:

  1. 将待更新的数据从磁盘加载到内存的缓冲池Buffer Pool中
  2. 写入undo日志便于进行回滚
  3. 写入redo日志到内存中的redo log buffer中
  4. 提交后,redo日志从内存中写到文件系统缓存中,并最终同步到磁盘中的redo日志文件中

redo和undo日志过程