数据库事务系列2 事务实现 redo
Posted 小耶哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库事务系列2 事务实现 redo相关的知识,希望对你有一定的参考价值。
3.事务的实现
事务的隔离性由锁来实现,原子性、一致性、持久性是通过数据库的redo log和undo log实现。
redo log称为重做日志,用来保证事务的原子性和持久性。Undo log用来保证事务的一致性。
有的DBA会认为undo是redo的逆操作,其实不然。
Redo和Undo都可以认为是一种恢复操作,redo恢复的是提交事务修改的页操作,undo是回滚行记录到某个特定的版本。
因此,两者记录的内容不同,redo通常是物理日志,记录的是页的物理修改操作;undo是逻辑日志,根据每行记录进行记录。
苏州天平山初冬美景 宋老师摄于2019年冬
4.redo
4.1 基本概念
重做日志由两部分组成:
1. 内存中的重做日志缓冲(redo log buffer), 其是易失的;
2. 重做日志文件(redo log file), 其是持久的;
InnoDB通过Force log at Commit机制实现事务的持久性,即当事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化,待事务commit操作完成才算完成。
这里的日志是指重做日志,由redo log和undo Log两部分组成。Redo log用来保证事务的持久性,undo log用来保证事务的一致性,帮助事务回滚及MVCC功能。Redo log基本上都是顺序写的,在数据库运行时不需要对redo log的文件进行读取操作。而undo log是需要随机读取的。
为了保证每次日志都写入重做日志文件,在每次将重做日志缓冲写入重做日志文件后,InnoDB存储引擎都需要调用一次fsync操作。因为重做日志文件打开并没有使用O_DIRECT选项,因此重做日志缓冲先写入文件系统缓存。为了确保重做日志写入磁盘,必须进行一次fsync操作。因为fsync的效率取决于磁盘的性能,因此磁盘的性能决定了事务提交的性能,也就是数据库的性能。
InnoDB存储引擎允许手动设置非持久性的情况,即当事务提交时,日志不写入重做日志文件,而是等待一个时间周期后再执行fsync操作,以此提高数据库的性能。但是,当数据库发生宕机时,由于部分日志未刷新到磁盘,会导致最后一段时间的事务丢失。
参数innodb_flush_log_at_trx_commit就是用来设置刷新到磁盘的策略。有以下几个值:
0:事务提交时不进行写入重做日志操作,这个操作尽在master thread中完成,master thread会每秒进行一次fsync操作。
1:默认值,表示事务提交时,必须调用一次fsync操作;
2:事务提交时将重做日志写入重做日志文件,单仅写入文件系统的缓存中,不进行fsync操作。在这个设置下,mysql发生宕机而操作系统不宕机,并不会导致事务的丢失。但是,操作系统宕机,重启数据库会丢失未从文件系统刷新到重做日志文件的那部分事务。
在Mysql数据库中还有一种二进制日志(binlog), 其用来进行POINT-IN-TIME的恢复及主从复制环境的建立。
Binlog与redo log的区别:
1. 重做日志是在存储引擎层产生的,而二进制日志是在Mysql数据库的上层产生的,而且mysql数据库中任何对数据库的修改都会产生binlog.
2. 两种日志记录的内容形式不同。Mysql数据上层的二进制日志是一种逻辑日志,其记录的是对应的sql语句。而InnoDB存储引擎层面的重做日志是物理格式的日志,其记录的是对于每个页的修改。
3. 两种日志记录写入磁盘的时间不同。二进制日志只在事务提交完成后进行一次写入。而重做日志在事务进行中不断写入,日志并不是随事务提交的顺序进行写入的。
4.2 log block
重做日志都是以512字节进行存储的。这意味着重做日志缓存、重做日志文件都是以块(block)的方式进行保存的,称之为重做日志块(log block)。
若一个页中产生的重做日志数量大于512字节,那么需要分割为多个重做日志块进行存储。
而且,因为重做日志块的大小和磁盘扇区的大小一样,都是512字节,因此,重做日志的写入可以保证原子性,不需要doublewrite技术。
重做日志块包括三个部分:日志块头,日志块尾,日志本身。
日志块头占12字节,尾占8字节,日志本身占492字节。
Redo Log Buffer
Log block |
Log block |
…… |
Log block |
Log block |
Log block header |
Log block 512 Bytes |
Log block tailer |
重做日志缓存块结构图
LOG_BLOCK_TRL_NO(4字节) |
LOG_BLOCK_HDR_NO(4字节) |
LOG_BLOCK_HDR_DATA_LEN(2字节) |
LOG_BLOCK_FIRST_REC_GROUP(2字节) |
LOG_BLOCK_CHECKPOINT_NO(4字节) |
LOG_BLOCK_HDR_NO:标记这个log block在log block buffer中的位置。
LOG_BLOCK_HDR_DATA_LEN:表示这个log block所占用的大小。
LOG_BLOCK_FIRST_REC_GROUP:表示这个log block中第一个日志所在的偏移量。
LOG_BLOCK_CHECKPOINT_NO:表示该log block最后被写入时的检查点第4字节的值。
LOG_BLOCK_TRL_NO:与LOG_BLOCK_HDR_NO值相同。
4.3 log group
log group为重做日志组,其中有多个重做日志文件。InnoDB存储引擎实际只有一个log group .
log grouo 是一个逻辑概念,并没有一个实际存储的物理文件来表示log group信息。
每个Log group中的日志文件大小相同。Innodb1.2以前,重做日志文件的总大小要小于4GB,1.2版本以后可以达到512GB。
Log buffer根据以下规则将log block刷新到磁盘:
1. 事务提交时;
2. 当log buffer中有一半的内存空间已经被使用;
3. Log checkpoint时。
对于log block的写入追加(append)在redo log file的最后部分,当一个redo log file被写满,会接着下一个写,使用方式为round-robin。
4.4 重做日志格式
不同的数据库操作会有对应的重做日志格式。因为InnoDB存储引擎的存储管理是基于页的,所以其重做日志格式也是基于页的。虽然不同数据的重做日志格式不同,但是头部格式相同。
Redo_log_type |
space |
Page_no |
Redo log body |
Redo_log_type:重做日志类型;
Space:表空间的ID;
Page_no:页的偏移量;
Redo log body: Redo_log_type不同会有不同的存储内容。
4.5 LSN
LSN是日志序列号(log sequence number), 占用8个字节,并且单调递增。
LSN表示的含义:
1. 重做日志写入的总量;
2. Checkpoint的位置;
3. 页的版本;
LSN表示事务写入重做日志的字节总量。
例如当前重做日志的LSN是1000,有一个事务T1写入了100个字节的重做日志,那么LSN就变成了1100.
LSN不仅记录在重做日志中,还存在于每个页中。在每个页的头部有一个FIL_PAGE_LSN, 记录了该页的LSN。在页中,LSN表示该页最后刷新时LSN的大小。
因为重做日志记录的是每个页的日志,因此页中的LSN用来判断页是否需要进行恢复操作。
例如,页P1的LSN是10000,而数据库启动时,innodb检测到写入重做日志中的LSN为13000,并且该事务已经提交,那么数据库需要进行恢复操作,并且将重做日志应用到P1页中。同样,对于重做日志中LSN小于P1页中的LSN, 不需要进行重做,因为P1页中的LSN表示页已经刷新到该位置。
可以通过show engine innodb status查看LSN的情况:
……
LOG
---
Log sequence number 103469321
Log flushed up to 103469321
Pages flushed up to 103469321
Last checkpoint at 103469312
……
Log sequence number表示当前的LSN,Log flushed up to表示刷新到重做日志文件的LSN,Last checkpoint at表示刷新到磁盘的LSN。
在生产环境中,Log flushed up to和Log sequence number可能是不同的,因为在一个事务中,从日志缓冲刷新到重做日志文件每秒都会发生。
4.6 恢复
由于checkpoint表示已经刷线到磁盘页上的LSN,因此在恢复过程中仅需恢复checkpoint开始的日志部分。
往期回顾
InnoDB存储引擎系列
75道BAJT高级Java面试题专题
运维专家专题
经典回顾
微信支付专题
参考资料
1 | CSDN
责编 | 小耶哥
本期作者 | 才高7缸
平台建设及技术支持 | 小耶哥
以上是关于数据库事务系列2 事务实现 redo的主要内容,如果未能解决你的问题,请参考以下文章
undolog实现事务原子性,redolog实现事务的持久性
数据库原理 - 序列3 - 事务是如何实现的? - Redo Log解析
InnoDB事务日志(redo log 和 undo log)详解