MySQL-InnoDB的事务日志

  笔者在阅读《高性能MySQL》的过程中,发现本书对事务日志的介绍过于晦涩也过于简略,因此结合自己的理解,详细地写一下事务日志。

  InnoDB的事务日志主要分为redo log(重做日志,提供前滚操作)和undo log(回滚日志,提供回滚操作),为了最大程度上减少数据写入时io问题,在存储引擎修改表的数据时,会将数据从磁盘拷贝到内存中,然后修改内存中的数据拷贝,再将修改行为持久化到磁盘中(先写redo log buffer(日志缓冲区)(PS:这块我会在下文详细说明),再定期批量写入),而不用每次将修改的数据本身持久化到硬盘中。

  (PS:这里笔者有个疑问,redo log本身是循环写,但事务日志是追加写,对此我猜测是因为redo log相对于需要写入的数据来说足够大,所以对单个事务的写入来说是追加写操作,但是从redo log整体来说,其空间是循环利用的,当空间占用到一定程度后,就会从头开始循环写数据。因此此处循环写和追加写的概念不冲突,这是笔者的猜想,水平有限可能并不准确,如果以后有了答案会来更新,当然如果有人知道也请不吝赐教)。

  当事务日志持久化以后,就会将脏数据慢慢写回磁盘中(这块下面我也会详细说),目前大多数存储引擎都是这么做的,这也被叫做预写式日志(Write-Ahead Logging),修改数据的时候需要进行两次写磁盘的操作。

  其实上面的概念都是老生常谈,下面我会详细地讲讲事务日志的各个部分。


 

  redo log_buffer

  事务日志本身也有缓存,这就是redo log_buffer(日志缓冲区),每次事务日志的写入并不会直接写入到文件中,而是会写入到缓冲区中,在一定事件的触发下,才会将缓冲区内的数据写入到日志文件中。

  也就是说,一个写操作在InnoDB引擎内部发生的事情其实是这样的:Write info -->redo log info-->redo log buffer -->redo log file -->file。

  innoDB_log_buffer_size的大小:

mysql> show variables like 'innodb_log_buffer_size%';
+------------------------+----------+
| Variable_name          | Value    |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
1 row in set (0.05 sec)

我电脑中的日志缓冲区大小是16777216,也就是16M。redo log buffer的空间不需要太大,因为每秒都会刷新缓存到日志文件,因此缓存空间只需要大过每秒产生的事务量就可以了。

  之前说在一定事件的触发下,才会将缓冲区内的数据写到日志文件中(LGWR),那么到底是哪些时间呢?其一,就是刚刚提到的,每一秒钟主线程都会自动刷新;第二,当事务提交时,也会将缓冲区中的数据刷新到文件中;最后,只要缓冲区中的剩余空间小于总空间的一半,就会立刻刷新数据。


  redo log

  redo log(重做日志)本身是数据库事务中至关重要的部分。因为如果没有redo log的话,每修改一次数据,就需要移动一次磁头,而且一旦在修改过程中服务器断电的话,就会造成无法想象的后果。因此,我们引入了redo log,每次修改数据的时候,只需要顺序移动磁头即可,效率很高,一旦出现崩溃的情况,未写入数据库的数据也不会影响事务的完整性。在引擎重启后,会自动恢复这部分修改的数据,将数据库恢复到之前的正常状态(也就是说不需要重做所有日志,只需要重做Check Point之后的日志就可以了),这就是crash safe。

  之前也说了redo log是循环写入数据的,每个InnoDB引擎至少有一个重做日志文件组,而每个重做日志文件组至少包含两个重做日志文件(ib_logfile0,ib_logfile1),当文件0写满后,就切换到文件1继续写;文件1写满了,就切换回文件0。

  在数据写入量比较大的时候,redo log的大小会影响到数据库的性能,太大的话,一旦需要恢复日志,就需要很长时间。太小的话,写入一个事务的时候可能需要多次切换重做日志文件,会导致性能抖动。

mysql> show variables like 'innodb_log_file_size';
+----------------------+----------+
| Variable_name        | Value    |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
1 row in set (0.00 sec)

  目前5.7.24-ndb-7.6.8-cluster-gpl 版本中的默认空间是48M,最大可以设置为4G。


 

  undo log

  undo log的作用是用来提供事务的回滚功能,以及多个行版本控制(MVCC),即非锁定读。undo log并不是redo log的逆向过程,事实上,二者都算是用来提供数据恢复的日志。不同的是,redo log是物理日志,而undo log是逻辑日志,比如我们执行了一条update更新操作,undo log就会将update的反向操作记录下来,而redo log则只会记录修改后的数据值。并且undo log本身也需要持久化支持,所以undo log也会产生redo log。

  不同于redo log是在一片连续的磁盘空间上,undo log则是在几片独立的磁盘空间中,笔者猜想这是为了效率考虑,可以同时处理多个事务的数据修改。

  总结一下,undo log是用来在事务失败后进行回滚(roll back),保证了事务的原子性。

  redo是用来恢复未写入data file里的已成功事务更新的数据,保证了事务的持久性。

  二者缺一不可,如果只有redo,就不能在事务提交前刷新脏数据,这样一旦处理大事务,内存的占用会高的让你无法想象;而只有undo的话,就必须要在事务提交前刷脏完成,否则一旦宕机,某些数据就会直接消失,破坏了持久性。

  这里解释下什么是脏数据,因为进行的修改并不会立刻持久化到硬盘空间中,就会造成有一段时间data file和redo log中的数据不一致,这就是脏数据。

  即使事务已经被提交了,undo log也不会被立刻删除,因为需要保证日后事务也可以进行回滚操作。当事务隔离级别为REAPEATABLE READ(可重复读,即MySQL默认的事务隔离级别)时,事务读取的都是开启事务时的最新提交行版本,只要事务不结束,该行版本就不能删除,即undo logo也不能被删除。

 

 

 

 

 

 

转载于:https://www.cnblogs.com/CNty/p/10943626.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值