undo log

undo log(回滚日志)记录了回滚操作,也就是当前创建的SQL语句的逆操作。当事务执行失败需要回滚的时候,MySQL会通过undo log对数据进行回滚。因此undo log保证了事务的原子性

undo log在事务开始前产生。事务在提交时,并不会立刻删除日志,Innodb会将该事务对应的undo log放入到删除列表中,通过后台线程进行回收处理。

此外,undo log 还应用于MVCC(多版本并发控制)。事务创建时,通过创建的Read View中的事务id与当前版本行的隐藏列trx_id进行对比,如果不满足条件则通过undo log一直往前回滚直到符合条件。

事务的隔离性和MVCC机制在另一篇文章也有总结,可以去看上一篇文章。

bin log

bin log 记录了对MySQL数据库执行的更改操作,并且记录了语句的发生时间、执行时长;但是它不记录select、show等不修改数据库的SQL。

bin log对于操作的记录模式有几种:

  1. STATEMENT:记录SQL语句,优点是需要的储存空间小,缺点是对于部分语句(now等)会造成数据不一致问题。
  2. ROW:记录每行具体数据,优点是保证数据一致性,缺点是占用空间大。
  3. REMIX:以上两种模式的混合模式,结合了以上两个模式的优点。

bin log日志的大小是理论无限的,这会大量占用储存空间,如果是DBA,需要定期对bin log 进行备份。

redo log

要知道磁盘的读写速度是很慢的,如果所有的数据都要立即写入磁盘,那储存性能将大幅降低。那么redo log里保存的就是要写入磁盘的数据,这个数据是物理的,也就是说是对特定块进行操作。

我们简单了解一下redo log的储存结构:
file

假设我们为redo log 分配了一组四个文件。redo log 里维护两个指针,分别是write pos 和 check point。图中可以看到,文件读写是一个循环结构,也就是指针会从文件0一直读到文件3,之后回到文件0.

在更新数据时,InnoDB会先对内存进行修改,并写入redo log且状态为prepare状态,然后将write pos后移一位。这个时候就认为数据以及写入了。

check point 的作用是将该条redo log写入磁盘,并且后移擦除该条redo log记录。

从图中我们可以看到,redo log 的大小是有限的,一旦redo log满了,如果需要写redo log,就需要先把一部分数据写入至磁盘。

通过redo log,如果数据库遭遇宕机重启等情况,InnoDB也可以根据redo log将数据写入磁盘,避免数据丢失,从而保证了crash-safe能力,也就是保证了事务的持久性

redo log 和 bin log 的区别

bin log 中记录的是逻辑操作,即操作语句之类的,而redo log 中记录的是物理操作,比如说将数据更新到指定磁盘块中。

bin log 大小不限,而redo log 大小有限。这以为者bin log更适合做数据备份。

bin log 是在server层实现的, 而redo log 是在InnoDB引擎实现的,redo log的出现是为了解决crash-safe的,也就是实现了事务的持久性,而MySIAM没有事务功能。

二阶段提交

我们现在知道了,bin log 可以用于数据备份, redo log 可以用于实现持久性。但是在日志写入过程中,如果两者分别写入日志,中途突然产生断电等情况,必然会导致bin log 和redo log数据不一致,从而导致数据恢复时候数据不一致的问题。

redo log 采用了两阶段提交,具体过程如下:

  1. 进行update操作。
  2. InnoDB将操作写入redo log日志,并更新内存,此时日志状态为prepare状态。
  3. server层将操作写入bin log日志中。
  4. 确认提交,redo log 将日志更新为commit状态,并写入磁盘。

因为redo log 和 binlog 有一个共同的数据字段,叫 XID。崩溃恢复的时候,会按顺序扫描 redo log:

  1. binlog中没有记录,回滚。
  2. binlog中有记录,将数据写入磁盘,并更新日志状态为commit。

这样就能保证数据备份时数据的一致性了。

参考资料

  1. MySQL中都有哪些日志文件?

  2. 为什么写入redo log和bin log要用两个阶段提交呢

  3. 极客时间 —— MySQL45讲:日志系统:一条SQL更新语句是如何执行的?

Categories:

Tags:

还没发表评论,快来发表第一个评论吧~

发表回复