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对于操作的记录模式有几种:
- STATEMENT:记录SQL语句,优点是需要的储存空间小,缺点是对于部分语句(now等)会造成数据不一致问题。
- ROW:记录每行具体数据,优点是保证数据一致性,缺点是占用空间大。
- REMIX:以上两种模式的混合模式,结合了以上两个模式的优点。
bin log日志的大小是理论无限的,这会大量占用储存空间,如果是DBA,需要定期对bin log 进行备份。
redo log
要知道磁盘的读写速度是很慢的,如果所有的数据都要立即写入磁盘,那储存性能将大幅降低。那么redo log里保存的就是要写入磁盘的数据,这个数据是物理的,也就是说是对特定块进行操作。
我们简单了解一下redo log的储存结构:
假设我们为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 采用了两阶段提交,具体过程如下:
- 进行update操作。
- InnoDB将操作写入redo log日志,并更新内存,此时日志状态为prepare状态。
- server层将操作写入bin log日志中。
- 确认提交,redo log 将日志更新为commit状态,并写入磁盘。
因为redo log 和 binlog 有一个共同的数据字段,叫 XID。崩溃恢复的时候,会按顺序扫描 redo log:
- binlog中没有记录,回滚。
- binlog中有记录,将数据写入磁盘,并更新日志状态为commit。
这样就能保证数据备份时数据的一致性了。
参考资料
-
极客时间 —— MySQL45讲:日志系统:一条SQL更新语句是如何执行的?
还没发表评论,快来发表第一个评论吧~