【Mysql】三大日志 redo log、bin log、undo log

【Mysql】三大日志 redo log、bin log、undo log

@[toc]

redo log(物理日志\重做日志)

redo log
是InnoDB存储引擎层的日志,又称重做日志文件,是物理日志。
redo log
记录数据修改后
新数据的备份、冗杂的
undo log
、未提交的事务和回滚的事务,数据缓存到内存中,只是在事务提交前将
redo log
持久化到磁盘

redo log
可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,保证了事务的 持久性

当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到

redo log
中,并更新内存。之后,InnoDB引擎会在适当的时候,将这个操作更新到磁盘中,这个更新是在系统比较空闲的时候做,他的关键点是先写日志,再写磁盘。

redo log
日志大小是固定的,若空间满了以后会回到头部停止更新,先加载一些数据到磁盘让出文件空间,之后继续写入


物理日志:因为

mysql
数据最终是保存在数据页中的,物理日志记录的就是数据页变更

为了保证Redo Log能够有比较好的IO性能,InnoDB 的 Redo Log的设计有以下几个特点:

尽量保持

Redo Log
存储在一段连续的空间上。因此在系统第一次启动时就会将日志文件的空间完全分配。以顺序追加的方式记录Redo Log,通过顺序IO来改善性能。

redo log包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。日志并不是直接写入文件的,而是先写入日志缓冲,当需要将日志刷新到磁盘时(如事务提交),将许多日志一起写入磁盘.

并发的事务共享

Redo Log
的存储空间,它们的
Redo Log
按语句的执行顺序,依次交替 的记录在一起,以减少日志占用的空间。所以,当一个事务将Redo Log写入磁盘时,也会将其他未提交**的事务的日志写入磁盘。

Redo Log
上只进行顺序追加的操作,当一个事务需要回滚时,它的
Redo Log
记录也不会从
Redo Log
中删除掉。


注意

一般在事务提交之前会将

redo log
持久化到磁盘中,以此来保证 持久性



binlog(逻辑日志/归档日志)

binlog
是属于MySQL Server层面的,又称为归档日志,属于逻辑日志,是以二进制的形式记录的是这个语句的原始逻辑,依靠
binlog
是没有
CrashSafe
能力的

逻辑日志:可以简单理解为记录的就是sql语句

binlog
主要使用场景:
主从复制
数据恢复

主从复制:在

Master
端开启
binlog
,然后将
binlog
发送到各个
Slave
端,
Slave
端重放
binlog
从而达到主从数据一致。

数据库恢复方法

系统会定期整库备份,binlog会记录所有的逻辑操作,当需要恢复到指定的某一时刻时:

首先,找到最近的一次全量备份 然后,从备份时间开始,将binlog依次取出来,一直重放到指定的时刻

为什么 redo log 具有 crash-safe 的能力,而 binlog 没有?

CrashSafe
指MySQL服务器宕机重启后,能够保证: - 所有已经提交的事务的数据仍然存在。 - 所有没有提交的事务的数据自动回滚。

当数据库 crash(崩溃) 后,想要恢复未刷盘但已经写入

redo log
binlog
的数据
到内存时,
binlog
是无法恢复的。虽然
binlog
拥有全量的日志,但没有一个标志让 innoDB 判断哪些数据已经刷盘,哪些数据还没有。

redo log
不一样,只要刷入磁盘的数据,都会从
redo log
中抹掉,数据库重启后,直接把
redo log
中的数据都恢复至内存就可以了。这就是为什么
redo log
具有
crash-safe
的能力,而
binlog
不具备。


redo log 和 binlog的区别:

redo log是InnoDB特有的日志, binlog 所有引擎都可以使用 redo log是物理日志,记录的是该数据页更新的内容;
binlog
是逻辑日志,记录的是这个更新语句的原始逻辑 redo log是循环写的,空间固定会用完。 binlog是可以追加写的,当 binlog写到一定大小会切换到下一个,并不会覆盖以前的日志 binlog可以作为恢复数据使用,主从复制搭建, redo log作为异常宕机或者介质故障后的数据恢复使用。

update语句执行流程

首先进行sql查询语句的执行流程,如需 update ID = 2 ,先找到这一行,执行以下流程:


为什么update语句 要有两阶段提交?

这是为了让两份日志之间的逻辑一致。

当执行update语句时,数据修改完更新到内存,先写

redo log
并设置
redo log
为准备阶段,再写
binlog
,写完
binlog
设置为
redo log
为结束阶段。两个中间有一个写入差错,那么该操作都是失败,即
redo log
发现只有准备阶段没有结束,那么会将该条事务进行回滚。


假如不采用两阶段提交机制的话那么会有什么影响呢? (1)先写

redo log
:当写完redo log设备断电,
binlog
没有记录,那么数据库刚刚启动之后通过
redo log
可以恢复到断电前的状态,但是由于
binlog
没有写入,当从某个节点进行恢复时(或者创建一个备份库),那么binlog没用这条记录,恢复出来的数据库是有错误的。 (2)先写
binlog
:当写完
binlog
设备断电,
redo log
没有记录,还没有写入磁盘,那么数据库重新启动之后通过
redo log
恢复并没有这条数据,而当从某个时间点进行恢复(或者创建一个备份库)时,
binlog
有相关数据,所以会导致数据不统一。



Uodolog(回滚日志/重做日志)

Undo Log 是为了实现事务的原子性,事务中执行失败,进行回滚,在MySQL数据库

InnoDB
存储引擎中,还用
Undo Log
来实现多版本并发控制(简称:
MVCC
)。由引擎层的 InnoDB引擎实现,是 逻辑日志,记录数据修改被修改前的值。


原理:

Undo Log的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到Undo Log。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。


回滚时机?

用户调用 rollback 主动回滚 事务出错 辅助 redo log 实现事务持久性

当事务提交的时候,

innodb
不会立即删除
undo log
,因为后续还可能会用到
undo log
,如隔离级别为
repeatable read
时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。

但是在事务提交的时候,会将该事务对应的

undo log
放入到删除列表中,未来通过purge来删除。并且提交事务时,还会判断
undo log
分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的
undo log
页而浪费存储空间和性能。

undo log+redo log保证持久性

除了可以保证事务的原子性,Undo Log也可以用来辅助完成事务的持久化,如数据库异常之后的恢复机制。

因为未提交的事务和回滚了的事务也会记录在

Redo Log
,因此在进行恢复时,这些事务要进行特殊的的处理。有2种不同的恢复策略:

进行恢复时,只重做已经提交了的事务。 进行恢复时,重做所有事务包括未提交的事务和回滚了的事务。然后通过 Undo Log回滚那些未提交的事务。

MySQL数据库InnoDB存储引擎使用了B策略,

InnoDB
存储引擎中的恢复机制有几个特点:

Undo Log回滚那些未提交的事务,被回滚了的事务在恢复时先

redo
undo
,也不会破坏数据的一致性

​ 必须要在写

Redo Log
之前将对应的
Undo Log
写入磁盘。为了降低复杂度,InnoDB将
Undo Log
看作数据,因此记录
Undo Log
的操作也会记录到
redo log
中。这样undo log就可以象数据一样缓存起来,而不用在
redo log
之前写入磁盘了。


参考:

极客时间 mysql45讲

https://www.qiancheng.me/post/coding/mysql-001

说说MySQL中的Redo log Undo log都在干啥 - 苏家小萝卜 - 博客园 (cnblogs.com)

详细分析MySQL事务日志(redo log和undo log) - 骏马金龙 - 博客园 (cnblogs.com)

MySQL事务日志undo log和redo log分析