MySQL事务日志

     我们知道,MySQL事务有4个特性:隔离性、持久性、原子性、一致性。事务的隔离性是由锁来实现的。原子性、一致性、持久性通过数据库的redo log和undo log来完成。redo log称为重做日志,用来保证事务的原子性和持久性。undo log用来保证事务的一致性。事务要保证 ACID 的完整性必须依靠事务日志做跟踪。

     至关重要的三种日志:

     binlog 二进制日志
     redo log 重做日志
     undo log 回滚日志

     一、redo log

     重做日志用来实现事务的持久性,即事务ACID中的D。

     1、作用

     redo通常是物理日志,记录的是页的物理修改操作,数据库崩溃则用其重做。

     2、组成

     其由两部分组成:

     1)内存中的重做日志缓冲(redo log buffer),其是易失的

     2)重做日志文件(redo log file),其是持久的

     3、如何保证事务的持久性?

     通过Force Log at Commit 机制,即当事务commit提交时,innodb引擎先将 redo log buffer 写入到 redo log file 进行持久化,待事务的commit操作完成时才算完成。这种做法也被称为 Write-Ahead Log(预先日志持久化),在持久化一个数据页之前,先将内存中相应的日志页持久化。

     4、工作流程

     1)事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲。

     2)在事务提交之前,缓冲的日志都需要提前刷新到磁盘上持久化,这就常说的“日志先行”(Write- Ahead-Logging)。

     3)当事务提交之后,在Buffer Pool 中映射的数据文件才会慢慢刷新到磁盘。

     4)此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据 redo log 中记录的日志,把数据库恢复到崩溃前的一个状态。

     5)未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。

     说明:在系统启动的时候,就已经为 redo log 分配了一块连续的存储空间,以顺序追加的方式记录 redo log,通过顺序 IO来改善性能。所有的事务共享 redo log 的存储空间,它们的 Redo Log 按语句的执行顺序,依次交替的记录在一起。

     5、持久化策略

     为了确保每次日志都能写入到重做日志文件中,在每次将 log buffer 中的日志写入日志文件的过程中都会调用一次操作系统的 fsync 操作

     6、重做日志文件写入流程

     先写重做日志文件1,当文件1被顺序写满时,会切换到重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中,依次循环; 所以说重做日志文件是循环覆盖写入的 。

     因为重做日志是循环覆盖写入的,所以不能使用其进行整个数据库的数据恢复,它只能保证数据库宕机时的事务的完整性数据;如果想要恢复全部数据的话,只能使用 binlog 二进制日志(归档日志)进行恢复。

     注意:大家可以手动修改重做日志文件组下的文件数量,并可以指定每个重做日志文件的大小,通过下面的参数:

     1)innodb_log_file_size 指定重做日志文件的大小

     2)innodb_log_files_in_group 重做日志文件组下的文件数量

     二、undo log

     1、作用

      undo log有两个作用:提供回滚和多个行版本控制(MVCC)。

      2、工作流程

      1)逻辑日志

      undo log 和 redo log 记录物理日志不一样,它是逻辑日志,根据每行记录进行记录,因此只是将数据库逻辑得恢复到原来的样子

      undo log 是逻辑日志,可以理解为:

      当 delete 一条记录时,undo log 中会记录一条对应的 Insert 记录

      当 insert 一条记录时,undo log 中会记录一条对应的 delete 记录

      当 update 一条记录时,它记录一条对应相反的 update 记录

      2)举例

      假设有 2 个数值,分别为 A=1 和 B=2, 然后将 A 修改为 3, B 修改为 4。

      下面是事务的整个工作流程:

       步骤1.  start transaction

       步骤2.  记录 A=1 到 undo log;  

       步骤3.  Update A=3

       步骤4.  记录 A=3 到 redo log

       步骤5.  记录 B=2 到 undo log 

       步骤6.  Update B=4

       步骤7.  记录 B=4 到 redo log

       步骤8.  将 redo log 刷新到磁盘

       步骤9.  Commit

       MySQL事务日志-冯金伟博客园

      在 1-8 步骤的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。

      如果在 8-9 之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时 redo log 已经持久化。

      若在 9 之后系统岩机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据 redo log 把数据刷回磁盘

      所以,redo log 其实保障的是事务的持久性和原子性,而 undo log,则保障了事务的一致性。

     三、binlog

      binlog 二进制日志(归档日志),这个日志是由MySql的 server层进行维护的;不管当前MySql使用的是什么存储引擎,binlog归档日志都是支持的.

      1、作用

      1)用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。

      2)数据恢复,用于数据库的基于时间点的还原。

      2、binlog的格式

      binlog 共有三种存储格式: row, statement 和混合模式。

      1)row: 记录哪行数据被修改的

      数据记录方式比较简单,但是可能会产生大量的数据废弃日志(如 更新一个全表)。

      2)statement: 记录修改数据的 SQL ,不记录修改的数据

      记录数据的过程,日志量比较小,IO 读写少。缺点是 有些函数并不支持,为了保证能够一致性,必须还需要有一些上下文的信息。

      3)混合模式:  是以上两种模式的混合使用,MySQL 会根据执行的每一条具体的 sql 语句来区分对待记录的日志形式。

      一般的语句修改使用 statment 格式保存 binlog ,如一些函数,statement 无法完成主从复制的操作,则采用 row 格式保存 binlog。

      3、与 redo 日志的区别

      1)redo 是 Innodb 存储引擎独有的,binlog 是所有引擎都可以使用的

      2)redo 是物理日志,记录的是在某个数据页上做了什么修改,binlog 是逻辑日志,记录的是这个语句的原始逻辑。

      3)redo 是循环写的,空间会用完,binlog 是可以追加写的,不会覆盖之前的日志信息。

      4)Binlog 中会记录所有的逻辑,并且采用追加写的方式

      注意:

      binlog二进制日志文件在默认情况下并没有启动,需要手动进行开启的。根据MySql的官网手册了解到,开启此日志会使性能下降1%左右,这个损失大体上是可以接受的。

 

      参考链接:

      https://cloud.tencent.com/developer/article/1780893

      https://segmentfault.com/a/1190000039715378