宋利兵 mysql_MySQL数据库InnoDB存储引擎Log漫游(3)

本文详细介绍了MySQL InnoDB存储引擎的Checkpoint机制和Buffer Pool管理算法,包括脏页、日志顺序号(LSN)、Sharp Checkpoint与Fuzzy Checkpoint的区别,以及幂等规则在恢复过程中的作用。此外,还讨论了Buffer Pool的LRU链表和flush_list,以及Mini-Transaction(MTR)的一致性设计。
摘要由CSDN通过智能技术生成

做者:宋利兵html

来源:MySQL代码研究(mysqlcode)mysql

0、导读

本文重点介绍了InnoDB的checkpoint和Buffer Pool管理算法

04 – Checkpointsql

理论上来讲,若是MySQL数据库InnoDB存储引擎的buffer足够大,就不须要将数据自己持久化。将所有的redo log从新执行一遍就能够恢复全部的数据。可是随着时间的积累,Redo Log会变的很大很大。若是每次都从第一条记录开始恢复,恢复的过程就会很慢,从而没法被容忍。为了减小恢复的时间,就引入了Checkpoint机制。数据库

在了解checkpoint原理以前,先看两个名词:缓存

- 脏页(dirty page)

若是一个数据页在内存中修改了,可是尚未刷新到磁盘。这个数据页就称做脏页。并发

- 日志顺序号(Log Sequence Number)

LSN是日志空间中每条日志的结束点,用字节偏移量来表示。在Checkpoint和恢复时使用。异步

- Checkpoint 原理

假设在某个时间点,全部的脏页都被刷新到了磁盘上.这个时间点以前的全部Redo Log就不须要重作了。系统记录下这个时间点时redo log的结尾位置做为checkpoint. 在进行恢复时,从这个checkpoint的位置开始便可。Checkpoint点以前的日志也就再也不须要了,能够被清除掉。为了更好的利用日志空间,InnoDB并不会删除之前的Redo Log文件. InnoDB用几个Redo Log文件首尾相连,构建了一个环形缓存(circular buffer)的日志空间。函数

- 有了Checkpoint以后的Recovery性能

A. 首先要按期的将Checkpoint写入磁盘中某个地方.

B. 作Recovery时,从磁盘中读出Checkpoint.

C. 根据Checkpoint中的LSN找到Redo Log相应的位置,开始执行Redo Log.

- Sharp Checkpoint

对于繁忙的系统来讲,不多会出现这样的的一个时间点。为了能创造出这样一个时间点,最简单的办法就是:

A. 在某个时间开始中止一切更新操做

B. 全部的脏页被刷新到磁盘

C. 记录当前Redo Log的结尾位置到磁盘上.

D. Checkpoint结束,继续更新操做。

08ba39af36e4475f96b8ad98.html

Sharp Checkpoint

这个方法称做Sharp Checkpoint,显然对于繁忙的系统, 这种方法是不合适的。能不能在checkpoint时不中止用户的操做呢?

- Fuzzy Checkpoint

如今咱们来看看,不中止更新操做的Checkpoint如何作:

A. 选取当前的Redo Log结束位置做为checkpoint点。

B. 将全部checkpoint点以前的脏页写入磁盘.

C. 将checkpoint点的位置持久化到磁盘上.

以下图所示,由于在刷脏页的同时用户还在更新数据,LSN1前的某个脏页在刷到持久存储以前就有可能会被LSN1以后的某个操做又给修改了。当刷脏页到磁盘时,LSN1后的部分操做(R1,R2对应的操做)就会被刷入磁盘。中止更新操做作checkpoint时(Sharp Checkpoint),持久存储中存储的数据是某个确切时间点的内存数据的快照。而不中止更新操做作checkpoint时,持久存储中存储的数据不是某个确切时间点的内存数据的快照。所以被称做Fuzzy Checkpoint.

08ba39af36e4475f96b8ad98.html

Fuzzy Checkpoint

- 幂等(Idempotence)规则

如上图所示,checkpoint 在LSN1位置,当checkpoint完成时R1,R2对应的修改也被刷到了持久存储。恢复时要从LSN1位置开始,包括R1, R2在内。虽然,R1,R2的数据已经被刷入持久存储中了,R1,R2两个Redo记录仍然会被从新执。从新执行后,数据还能正确吗?

这就要求InnoDB的Redo Log要知足幂等规则。幂等规则要求不管redo log被重复执行了多少次,数据始终正确。

- 物理日志自然知足幂等规则

- 逻辑日志须要特殊处理才能支持幂等规则

前面说过InnoDB的Redo Log是物理到页,页内是逻辑日志。所以须要特殊处理,才能知足幂等规则。

- 数据页的最新(最大)LSN

为了知足幂等规则,InnoDB中每一个数据页上都记录有一个LSN。每次更新数据页时,将LSN修改成当前操做的redo log的LSN。在恢复时,若是数据页的LSN大于等于当前redo log的LSN,则跳过此日志。

- 异步Checkpoint

实现了幂等规则后,脏页就能够在任什么时候间,以任何顺序写入持久存储了。InnoDB的buffer pool有一套单独的机制来刷脏页。所以不少状况下checkpoint时,并不须要写脏页到存储。只是将全部脏页的最小的LSN记作checkpoint.这被称做“异步checkpoint"(不刷脏页到持久存储)

checkpoint的实如今log0log.c.

log_checkpoint()实现异步checkpoint.

- 同步Checkpoint

InnoDB的buffer pool经过LRU的算法来决定哪些脏页应该被写入持久存储。若是包含最小LSN的页面频繁的被更新,它就不会被刷到存储上。这样就可能致使checkpoint点很长一段时间没法前进,甚至致使日志空间被占满。这时就要按照LSN由小到大的顺序写一部分脏页到持久存储。这被称作"同步Checkpoint"(要刷脏页到持久存储).

log_checkpoint_margin().

log_calc_max_ages()用来计算,‘判断是否要执行同步checkpoint’用到的参数.

05 – 缓存池(Buffer Pool)

学习到这里,我更倾向于说这是一个”Redo+Undo+Buffer”的模式。为了提搞IO性能,脏页缓存在buffer中,Redo log也要先缓存在内存中,doublewrite也有内存buffer.

InnoDB实现了一套Buffer 机制,称做Buffer pool,将存储在文件中的数据以页为单位映射到内存中.

- Buffer Pool的页分类

Buffer pool内的页分为三种:

A. 未被使用的页(空白的buffer),没有映射到一个数据文件中页。

B. 净页,映射到了一个数据文件页,并且没有被修改过。内容和数据文件的页同样。

C. 脏页,映射到了一个数据文件页,而且数据被修改过。内容和数据文件的页不同。

- Buffer Pool的LRU页表

InnoDB维护了两个LRU链表。当空间不足时,用来决定哪些脏页应该被首先写入磁盘,哪些净页应该被释放掉。

A. buffer_pool->LRU,普通LRU链表,记录全部数据缓冲页。

B. buffer_pool->unzip_LRU,是压缩页(row_format=compressed)解压后数据缓冲页LRU链表。

LRU链表中的页面按最近一次的访问的时间顺序排列,头部是最近一次被访问的页面,尾部是最先一次被访问的页面。不管是读仍是写一个页面上的数据,都要先获取这个页面。所以能够在获取页面时,维护LRU链表.当获取一个页面后,将其放到LRU链表的头部便可。

buf_page_get_gen()和buf_page_get_zip()用来获取一个页面,他们调用

buf_unzip_LRU_add_block()和buf_page_set_accessed_make_young()来维护LRU链表。

- flush_list

同步checkpoint时,须要根据数据页修改的前后顺序来将脏页写入持久存储。所以除了LRU链表,buffer pool中还有一个按脏页修改前后顺序排列的链表,叫flush_list.当须要同步checkpoint时,根据flush_list中页的顺序刷数据到持久存储。

A. 一个页只在flush_list中出现1次,由于一个页面只须要写一次。

B. 按页面最先一次被修改的顺序排列。

06 – Mini-Transaction(MTR)

前面提到Redo Log将数据的操做细分到了页面级别。可是有些在多个页面上的操做是逻辑上不可分裂的。InnoDB中用Mini-Transaction来表示这些不可再细分的逻辑操做。

- MTR的一致性

为了知足MTR的一致性,MTR作了以下的设计:

A. MTR的全部日志被封装在一块儿,当MTR提交时一块儿写入redo log buffer.这样作有2个好处:

* 减小并发MTR对redo log buffer 的竞争。

* 连续的存储在一块儿,恢复时的处理过程更简单。

B. InnoDB在redo log的层面,将一个MTR中的全部日志做为Redo log的最小单元。在恢复时,一个MTR中的全部日志必须是完整的才能进行恢复。

- MTR日志的封装

为了在日志文件中区分不一样的MTR,MTR将MLOG_SINGLE_REC_FLAG或MLOG_MULTI_REC_END写入redo log(mtr_log_reserve_and_write()).

A. 若是MTR的日志中只有一行记录,在日志的开始处添加MLOG_SINGLE_REC_FLAG,表示MTR中只有一条记录。

B. 若是MTR的日志中有多行记录,在日志的结尾处添加一个类型为MLOG_MULTI_REC_END的日志,表明MTR的日志到此结束.

- MTR的LSN

A. 由于在将日志写入redo log buffer时,才能得到LSN。因此修改数据时,并无修改页上的LSN。须要在MTR得到LSN后统一修改。

B. 一个MTR只有一个LSN. 一个MTR内修改的全部页的LSN相同。这样checkpoint就不会出如今MTR的中间。

C. 在得到LSN后,若是被MTR修改的脏页不在buffer pool的flush_list里,就会被添加进去。看mtr_memo_slot_note_modification()和buf_flush_note_modification().

- 页级锁

MTR提交时才写日志到redo log的作法,决定了MTR要使用页级锁。

A. 一个页面不能同时被多个活动的MTR修改。

B. MTR中数据页的锁,直到MTR提交时(日志写入redo log buffer)后才释放。

锁对象存储在mtr的memo中。调用mtr_s_lock和mtr_x_lock来加锁时,锁对象被保存到memo中。解锁在mtr_memo_slot_release()中完成。

- MTR的ROLLBACK

看完MTR的代码发现mtr没有记录undo日志,也不能rollback. MTR都是很小的操做单元,并且每一个MTR都有明确的操做目标,所以比较容易保证其正确性。

A. 由于页面操做是在内存中完成,而且页面有固定的格式,所以不少的页面操做是不会失败的。InnoDB存储引擎中的不少写页面的函数都没有返回值.

B. 在对任何页面操做前,先要检查是否可能发生错误。若是可能发生错误就不能往下执行。如,当插入一行记录到B-Tree的节点时,首先检查页面有足够的空间。

C. 使用更大粒度的锁(如B-Tree的锁),而且按照必定的顺序加锁。这样才能不致使死锁问题。以上是本身看代码后的大概印象,不必定说到了正点上。MTR模块的代码虽简单,可是MTR在其余模块大量的使用。要透彻的理解MTR,估计还得要看其余模块的代码,整理出来大部分MTR操做过程才行.

06 – 参考

A. Database Systems: The Complete Book (2nd Edition)

B. Transaction Processing: Concepts and Techniques

C. how-innodb-performs-a-checkpoint

D. InnoDB fuzzy checkpoints

E. Heikki Tuuri Innodb answers – Part I

F. Heikki Tuuri Innodb answers – Part II

其余相关阅读

推荐订阅原文做者 宋利兵的公众号 MySQL代码研究

08ba39af36e4475f96b8ad98.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值