理解MySQL的Redo日志和Undo日志
- 1、MySQL 日志文件解决的问题
- 2、redo 日志
- 2.1、redo log 的组成
- 2.2、redo log 刷盘策略
- 2.3、MySQL 的 redo log解决了哪些问题
- 3、undo 日志
- 3.1、undo 日志作用
- 3.2、undo log 的类型
- 3.3、undo log 的生命周期
- 3.4、事务回滚相关的几个隐藏字段
1、MySQL 日志文件解决的问题
事务有 4 种特性(CAID):原子性、一致性、隔离性和持久性。
- 事务的隔离性由
锁机制
实现。 - 事务的原子性、一致性、持久性由事务的 redo 日志和 undo 日志来保证。
redo log
称为重做日志
,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性
。undo log
称为回滚日志
,回滚行记录到某个特定版本,用来保证事务的原子性、一致性
。
关于 MySQL 的几种日志 :
redo log
:是存储引擎层(InnoDB)生成的日志
,记录的是物理级别
上的页修改操作,比如页号xxx、偏移量yyy 写入’ddd’ 数据,主要为了保证数据的可靠性。undo log
:是存储引擎层(InnoDB)生成的日志
,记录的是逻辑操作日志
,保证了事务的原子性。例如当对某一条数据做 insert操作时,那么 undo log 会记录一条与之相反的 delete 操作。主要用于事务的回滚
(undo log 记录的是每个修改操作的逆操作)和一致性非锁定读
(undo log 回滚行记录到某条特定的版本-----MVCC,即多版本并发控制)。bin log
: 是数据库层产生的
。
2、redo 日志
2.1、redo log 的组成
InnoDB 存储引擎是以
页为单位
来管理存储空间的。在真正访问页面之前,需要把在磁盘上的页缓存到内存中的 Buffer Pool 之后才能访问
。所有的变更都必须先更新缓冲池中的数据
,然后缓冲池中的脏页会以一定的频率被刷入磁盘(checkPoint机制)
,通过缓冲池来优化 CPU 和磁盘之间的鸿沟,这样就可以保证整体的性能不会下降太快。
关于 redo 日志的组成:redo log 的写入并不是直接写入磁盘的,InnoDB 引擎会在写 redo log 的时候先写 redo log buffer,之后以一定的频率(根据刷盘策略)
刷入到真正的 redo log file 中。
-
重做日志的缓冲(redo log buffer)
,保存在内存中,是易丢失的。在服务器启动时,就像操作系统申请了一大片叫做 redo log buffer 的
连续内存
空间(redo日志缓冲区),该空间被划分成若干连续的 redo log block. -
重做日志文件(redo log file)
,保存在磁盘中,是持久的。
redo log 存储表空间ID、页号、偏移量以及需要更新的值,所需要的存储空间是很小的
,刷盘快(降低了刷盘频率)
。其特点是:
-
redo 日志是顺序写入磁盘的
。在执行事务的过程中,每执行一条语句,可能会产生多条redo日志,且这些redo日志是按照产生的顺序写入磁盘的,也就是使用顺序IO,效率比随机IO快
。 -
事务执行过程中,redo log不断记录
。假设一个事务,需要 insert 5万条数据,在这个过程中,一直不断的往 redo log 顺序记录。而bin log 是直到事务提交,才会一次写入到 bin log 文件中。
2.2、redo log 刷盘策略
redo log buffer 刷盘到 redo log file 的过程,并没有真正刷到磁盘中,只是刷到了**
文件系统缓存(page cache)
**,真正的写入会交给系统自己来决定(比如当page cache 足够大了)。所以,对于存储引擎 InnoDB而言存在一个问题,如果交给系统来同步,如果系统宕机,也会丢失数据。由此原因,InnoDB 给出了
innodb_flush_log_at_trx_commit
参数,该参数控制提交事务时,如何将 redo log buffer 中的日志刷新到 redo log file 中。
innodb_flush_log_at_trx_commit
参数说明:
参数值 | 参数值说明 |
---|---|
0 | 每次事务提交时不进行刷盘操作,系统默认 master thread 每隔 1 秒进行一次redo log 的同步。 |
1 | 每次事务提交时,都将进行同步,刷盘操作(默认值)。 |
2 | 每次事务提交时,只把redo log buffer内容写入 page cache,但不进行同步,由OS自己决定什么时候同步到磁盘文件。 |
注意:另外,InnoDB 引擎有一个后台线程,每隔 1 秒,会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用刷盘操作
。因为在事务执行过程中, redo log 记录是会写入 redo log buffer 中的,这些 redo log 记录可能会被后台线程
刷盘,所以一个没有提交事务的 redo log 记录,也可能刷盘
。
-
值为1 时,只要事务提交成功,redo log 记录就一定在硬盘里,不会有任何数据丢失。如果事务执行期间 MySQL 挂了或宕机,这部分日志丢了,但是事务并没有提交,所以日志丢了也不会有损失,可以保证 ACID 中的 D,
数据绝对不会丢失
,但是效率是最差的
。建议使用默认值,虽然操作系统宕机的概率理论小于数据库宕机的概率,但是一般既然使用了事务,那么数据的安全相对来说更重要些。 -
值为0时,master thread 中的每一秒进行一次重做日志的 fsnc 操作,因此实例 crash 最多丢失 1秒钟内的事务(master thread 是负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性)。
数值为 0 的话,它的 IO 效率理论高于 值为 1 ,低于值为 2 . 这种策略也有丢失数据的风险,无法保证 D
.
2.3、MySQL 的 redo log解决了哪些问题
事务的持久性
:redo log确保在事务提交后,即使数据库发生故障或崩溃,也能恢复和持久化事务的更改。通过redo log,MySQL能够在重启后重新执行未写入数据文件的更改,保证数据的一致性和持久性。数据恢复
:在数据库崩溃或发生故障时,redo log可以作为恢复数据的重要手段。通过重做日志中的记录,MySQL可以将未提交的事务进行回滚,将已提交但未写入数据文件的事务进行恢复,以确保数据库的一致性。减少磁盘I/O操作
:redo log的存在可以减少对磁盘的I/O操作。相比于每次事务提交都直接写入数据文件,MySQL可以先将事务的更改写入redo log并刷盘,然后在适当的时机异步地将这些更改应用到数据文件中。这样可以减少磁盘I/O的次数,提高数据库的性能。
总而言之,MySQL的redo log解决了事务持久性、数据恢复和性能优化等方面的问题,确保数据库在故障或崩溃时能够保持数据的一致性和可恢复性,同时提升了数据库的整体性能。
3、undo 日志
3.1、undo 日志作用
-
①
回滚数据
-
undo log 是逻辑日志,其将数据库逻辑地恢复到原来的样子,所有修改都被逻辑地取消了,但是数据结构和页本身在回滚之后可能大不相同。
这是因为在多用户并发系统中,可能会有数百上千的并发事务。数据库的主要任务是协调对数据记录的并发访问。比如,一个事务在修改当前一个页中某几条记录,同时还有其他事务在对同一个页中另几条记录进行修改,所以为保证不影响其他事务正在进行的工作,不能将一个页回滚到事务开始的样子。
-
-
②
MVCC
- 在 InnoDB 存储引擎中 MVCC的实现是通过 undo log 来完成的。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过 undo 读取之前的行版本信息,以此实现非锁定读取。
undo log 的产生会伴随着 redo log 的产生,因为 undo log 也需要持久性的保护。
3.2、undo log 的类型
在InnoDB 存储引擎中,undo log 分为:
-
①
insert undo log
- insert undo log 是指在 insert 操作中产生的 undo log。因为insert 操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该 undo log 可以在事务提交后直接删除,不需要进行 purge 操作。
-
②
pdate undo log
-
update undo log 记录的是对 delete 和 update 操作产生的 undo log,该 undo log 可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除。提交时放入 undo log 链表,等待 purge 线程进行最后的删除。
purge 线程两个主要作用:清理undo页和清除page里面带有Delete_Bit标识的数据行。在 InnoDB 中,事务中的 delete 操作实际上并不是真正的删除掉数据行,而是一种 Delete Mark 操作,在记录上标识 Delete_Bit,而不删除记录,真正的删除是后台 purge线程去完成。
-
3.3、undo log 的生命周期
举例说明undo log 的生命周期,假设 有两个数值 A = a1, B =b1,然后将 A 修改为a2,将 B 修改为 b2.
1. start transaction;
2. 记录 A=a1 到 undo log;
3. update A=a2;
4. 记录 A=a2 到 redo log;
5. 记录 B=b1 到 undo log;
6. update B=b2;
7. 记录 B=b2 到redo log;
8. 将 redo log 刷新到磁盘;
9. commit;
- 在1-8 步骤的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。
- 如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log 已经持久化。
- 若在9步之后
系统宕机
,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复后,可以根据redo log 把数据刷会磁盘。
3.4、事务回滚相关的几个隐藏字段
对于InnoDB引擎来说,每个行记录除了记录本身的数据之外,还存在几个隐藏的列。
DB_ROW_ID
:如果没有为表显式的定义主键,并且表中也没有定义唯一索引,那么InnoDB会自动为表添加一个 row_id 的隐藏列作为主键。DB_TRX_ID
:每个事务都会分配一个事务ID,当对某条记录发生变更时,就会将这个事务的事务ID写入 trx_id 中。DB_ROLL_PTR
:回滚指针,本质上就是指向 undo log 的指针。
.