MySQL InnoDB Update和Crash Recovery流程详解
1.2.3 什么是Log Sequence Number (LSN)?
一个64位无符号整数,表示Redo Log系统中的时间点,也是事务写入Redo Log的字节总量,从日志初始化开始计数(数据库初始化安装时间点开始且单调递增)
LSN不仅存在于Redo Log中,在每个数据页中都保存着一个LSN,在进行数据恢复时通过LSN做比较运算可以判断出每个数据页是否需要进行恢复操作
1.2.4 什么是Checkpoint?
一个时间点,由一个LSN值(Checkpoint LSN)表示的整型值,在Checkpoint LSN之前的每个数据页(buffer pool中的脏页)的更改都已经落盘(刷新到数据文件中),Checkpoint 完成后,在Checkpoint LSN之前的Redo Log就不再需要了。
Checkpoint技术是为了解决:全量Redo Log恢复时间太长、buffer pool中的空闲页不够用时将脏页刷新到磁盘数据文件、Redo Log空间不够用时将脏页刷新到磁盘数据文件等问题。
Checkpoint方式有两种:Sharp Checkpoint和Fuzzy Checkpoint(又可根据不同的场景细分)
Sharp Checkpoint:将所有的脏页刷回磁盘,数据库实例关闭时系统参数innodb_fast_shutdown设置为0,才需要把所有的脏页都刷回磁盘,刷脏时系统hang住
Fuzzy Checkpoint:持续的每次只刷新一部分脏页到磁盘,数据库正常运行过程中都是使用这种方式刷脏,在InnoDB内部还可细分为如下几种:
Master线程每秒/每十秒固定执行Checkpoint
LRU list中空闲页不够时,触发Checkpoint从LRU list刷新脏页以释放足够的空闲页
Redo Log空间不够时,触发Checkpoint从Flush list刷新脏页,Checkpoint执行完成之后,在这个位置之前的Redo Log不再需要(即,可以循环覆盖使用)
脏页太多达到脏页比例阀值(系统参数innodb_max_dirty_pages_pct和innodb_max_dirty_pages_pct_lwm控制脏页比例阀值),触发Checkpoint
1.2.5 什么是Rollback Pointer (ROLL_PTR)?
一个由rollback segment number、page number和page offset组成的指针,指向Undo Log中包含之前版本数据的具体Undo Log日志记录。
可用于为任何数据记录回退到一个历史版本记录、可用于mvcc中重建旧版本记录、可用于事务回滚。
1.2.6 什么是Transaction ID (TRX_ID)?
表示事务开始点的一个64位无符号整数
每个事务的事务号增量增加
事务号会写入聚簇索引的每个记录中
最大事务号会写入系统表空间的TRX_SYS页
1.2.7 什么是Transaction Serialization Number(TRX_NO) ?
一个64位无符号整数,表示事务提交时的最大TRX_ID
TRX_NO在事务提交时会写入Undo Log Header
TRX_NO可用于purge Undo Log中的旧版本记录
2. Update流程2.1 事务start(事务首次开启)
为这个事务分配事务ID(TRX_ID),该事务ID可能被写入系统表空间的TRX_SYS页面中的最大的事务ID字段(Transaction ID)
* 如果系统表空间的TRX_SYS页面中的最大的事务ID字段被更新,则该更新会被记录到Redo Log中。
根据分配的TRX_ID创建read view。
2.2 记录修改(每次只修改一行记录)
分配Undo Log日志空间
拷贝该记录修改之前的值到Undo Log中
将Undo Log的修改记录写入Redo Log中
在buffer pool中修改数据页,回滚段指针指向Undo Log中该记录之前的版本
将该记录对应的数据页变更部分写入Undo Log中
buffer pool中该记录修改之后的数据页被标记为”脏页”(需要刷新到磁盘的数据页)
2.3 此时其他事务的修改会怎样?
一旦记录被修改,即使没有提交,其他事务也可能会看到被修改后的记录,这依赖于他们的事务隔离级别而定:
如果是RU隔离级别,则使用索引页读取最新版本记录
如果是RU隔离级别,则查找记录的最新提交版本
如果是RR隔离级别,则查找与其read view相对应的记录版本
任何需要使用索引页来读取比最新的版本记录旧的版本记录时,都必须使用Undo Log来重建之前的版本记录。
2.4 事务提交(显式和隐式提交)
事务对应的Undo Log页被设置为”purge”(意味着当这个Undo Log页不再被任何其他事务引用时可以将其清除)
将Undo Log的修改记录写入Redo Log中
Redo Log Buffer刷新到磁盘(是否刷盘取决于系统变量innodb_flush_log_at_trx_commit的设置)
2.5 后台线程刷脏(后台线程连续不断地根据不同触发机制触发刷新)
查找最旧的“脏”页面(修改时间最早的页面)并将其添加到flush batch中
确保在flush batch中中最新的LSN号已经写入到了Redo Log中且已经落盘
如果开启了双写,则先将脏页刷新到双写缓冲区(并等待同步)
将每个脏页从buffer pool中写入最终目的地:表空间文件中的
PS:对于后台线程刷脏部分,执行刷新脏页时,与该脏页的事务是否提交无关,只需要确保该页对应LSN号的Redo Log记录落盘,而不会去判断事务的状态是否是提交还是未提交状态,因为,数据页结构中并没有地方单独记录事务的状态(即,无法判断事务是否提交),只是在每行数据中有记录事务号、回滚段指针(所以一个页中也可能包含多个事务的修改记录)。当需要对某个事务进行回滚时,重新从表空间中读取这个未提交的脏页,使用undo log中的反向数据进行反向修改,然后再重新刷脏。
2.6 定期执行Checkpoint
确保比Checkpoint 点更旧(比Checkpoint LSN小)的脏页已刷新到表空间文件,如果存在有比Checkpoint LSN大的脏页,则立即刷新脏页到数据文件中。说白了Checkpoint机制主要作用就是用于刷新脏页。
把Checkpoint LSN写到Redo Log Header中 (从这个Checkpoint LSN开始,之前的Redo Log记录不再需要)。
2.7 后台线程Purge(后台线程连续不断地根据需要定期执行Purge,包括Undo Log和历史链表)
查找每个回滚段中不再需要的最旧的Undo Log
实际上是从索引中删除任何带有删除标记的记录
释放Undo Log页
修剪history lists
3. Creash Recovery流程3.1 什么时候会进行Crash Recovery?
实例崩溃之后重启
使用一个备份还原(如:LVM 快照、xtrabackup备份)后
在“快速”(innodb_fast_shutdown不为0值关闭实例)关闭实例后重新启动
3.2 检测实例是不是干净地关闭的
打开Redo Logs和系统表空间文件(ibdataN)
读取并从中找到最大的Checkpoint LSN
从最近的Checkpoint 开始往后扫描Redo Log
如果能够找到Redo Log记录,说明还有数据页的更改没有刷新到数据文件上,启动Crash Recovery,使用Redo Log来恢复数据的一致性
3.3 使用所有独立表空间的表名和表空间ID创建一个名称到ID的映射
打开datadir下的所有.ibd文件
在这些表空间文件的offset 0的页(FSP_HDR页)头读取其表空间ID(FSP_HDR页中FSP Header的前四个字节记录着表空间ID)
将表空间ID与表名建立映射
非常好我支持^.^
(1) 100%
不好我反对
(0) 0%