美文网首页
mysql数据库InnoDB存储引擎Log漫游(3)

mysql数据库InnoDB存储引擎Log漫游(3)

作者: 快点给我想个名 | 来源:发表于2019-06-24 17:45 被阅读0次

原文地址http://www.zhdba.com/mysqlops/2012/04/06/innodb-log3/

Checkpoint

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

- 脏页(dirty page)
如果一个数据页在内存中修改了,但是还没有刷新到磁盘。这个数据页就称作脏页。

- 日志顺序号(Log Sequence Number)
LSN是日志空间中每条日志的结束点,用字节偏移量来表示。在Checkpoint和恢复时使用。

- 原理
假设在某个时间点,所有的脏页都被刷新到了磁盘上.这个时间点之前的所有Redo Log就不需要重
做了。系统记录下这个时间点时redo log的结尾位置作为checkpoint. 在进行恢复时,从这个
checkpoint的位置开始即可。Checkpoint点之前的日志也就不再需要了,可以被删除掉。为了
更好的利用日志空间,InnoDB以环形缓存(circular buffer)的方式来使用日志空间。

sharpcheckpoint1.jpg
  • Sharp Checkpoint
    对于繁忙的系统来说,很少会出现这样的的一个时间点。为了能创造出这样一个时间点,最简单的办
    法就是,在某个时间开始停止一切更新操作,直到所有的脏页被刷新到磁盘,Checkpoint被记录。
    显然对于繁忙的系统, 这种方法是不合适的。能不能在checkpoint时不停止用户的操作呢?

  • Fuzzy Checkpoint
    如下图所示,如果刷脏页的同时用户还在更新数据,LSN1前的某个脏页在刷到持久存储之前就有可能被
    LSN1之后的某个操作给修改了。当checkpoint完成时,LSN1后的部分操作(R1,R2对应的操作)也被
    持久化了。当Sharp checkpoint完成时,持久存储中存储的数据是某个确切时间点的内存数据的快照。
    Fuzzy checkpoint完成时,持久存储中存储的数据不是某个确切时间点的内存数据的快照。从某种
    程度上,可以说持久存储中的数据丧失了一致性。在恢复时,必须要解决这个问题。


    fuzzycheckpoint11.jpg
  • 幂等(Idempotence)规则
    如上图所示,checkpoint 在LSN1位置,当checkpoint完成时R1,R2对应的修改也被刷到了持久存储。
    恢复时要从LSN1位置开始,包括R1, R2在内。重新执行后,数据还能正确吗?
    幂等规则要求无论redo log被执行了多少次,数据始终正确。
    InnoDB的redo log, 物理到Page,Page内是逻辑日志。
    物理日志,天然支持幂等规则. 但是逻辑日志 需要特殊处理,才能支持满足幂等规则。

  • 数据页的最新(最大)LSN
    为了满足幂等规则,InnoDB中每个数据页上都记录有一个LSN。每次更新数据页时,将LSN修改为
    当前操作的redo log的LSN。在恢复时,如果数据页的LSN大于等于当前redo log的LSN,则跳过此
    日志。

  • 异步Checkpoint
    实现了幂等规则后,脏页就可以在任何时间,以任何顺序写入持久存储了。InnoDB的buffer pool有
    一套单独的机制来刷脏页。因此很多情况下checkpoint时,并不写脏页到存储。只是将所有脏页的
    最小的LSN记做checkpoint.
    checkpoint的实现在log0log.c.
    log_checkpoint()实现异步checkpoint.

  • 同步Checkpoint
    InnoDB的buffer pool通过LRU的算法来决定哪些脏页应该被写入持久存储。如果包含最小LSN的
    页面频繁的被更新,它就不会被刷到存储上。这样就可能导致checkpoint点很长一段时间无法前进,
    甚至导致日志空间被占满。这时就要按照LSN由最小到大的顺序写一部分脏页到持久存储。
    log_checkpoint_margin().
    log_calc_max_ages()用来计算,‘判断是否要执行同步checkpoint’用到的参数.

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

  • 页分类
    Buffer pool内的页分为三种:
    A. 未被使用的页(空白的buffer),没有映射到一个数据文件中页。
    B. 净页,映射到了一个数据文件页,而且没有被修改过。内容和数据文件的页一样。
    C. 脏页,映射到了一个数据文件页,并且数据被修改过。内容和数据文件的页不一样。

  • LRU
    InnoDB维护了两个LRU列表。当空间不足时,用来决定哪些脏页应该被首先写入磁盘,哪些净页应该被释放掉。
    A. buffer_pool->LRU,普通LRU链表,记录所有数据缓冲页。
    B. buffer_pool->unzip_LRU,是压缩页(row_format=compressed)解压后数据缓冲页LRU链表。
    LUR链表中的页面按最近一次的访问的时间顺序排列,头部是最后一次被访问的页面,尾部是最早一次被
    访问的页面。无论是读还是写一个页面上的数据,都要先获取这个页面。因此可以在获取页面时,维护
    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().

  • 页级锁
    提交时才写日志到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操作过程才行.

相关文章

  • MYSQL REDO UNDO

    本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo Log Undo Log 是为了实...

  • InnoDB学习笔记(3)Redo log

    MySQL · 引擎特性 · InnoDB redo log漫游MySQL · 引擎特性 · The design...

  • MySQL存储引擎

    MySQL:单进程多线程数据库 一、InnoDB存储引擎InnoDB存储引擎支持事务(5.5.8MySQL默认版本...

  • mysql数据库InnoDB存储引擎Log漫游(3)

    原文地址http://www.zhdba.com/mysqlops/2012/04/06/innodb-log3/...

  • 浅谈InnoDB存储引擎中的锁

    InnoDB存储引擎是MySQL数据库默认的事务型存储引擎,也是使用比较多的存储引擎。InnoDB存储引擎不紧支持...

  • Mysql数据引擎

    InnoDB数据存储引擎(Mysql5.5+ 默认数据存储引擎)主要特性: InnoDB引擎提供了对数据库ACID...

  • MySQL-存储引擎

    零、本文纲要 一、MySQL存储引擎 二、InnoDB存储引擎1、InnoDB逻辑存储结构2、InnoDB架构3、...

  • MySQL数据库引擎

    MySQL数据库引擎有哪些 mysql的存储引擎包括:MyISAM 、 InnoDB 、 BDB 、 MEMORY...

  • InnoDB学习笔记(2)Undo log

    MySQL · 引擎特性 · InnoDB undo log 漫游 INSERT操作在事务提交前只对当前事务可见,...

  • 快速理解InnoDB

    熟悉 MySQL 的人,都知道 InnoDB 存储引擎,如大家所知,Redo Log 是 innodb 的核心事务...

网友评论

      本文标题:mysql数据库InnoDB存储引擎Log漫游(3)

      本文链接:https://www.haomeiwen.com/subject/qznoqctx.html