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