MySQL技术:InnoDB存储引擎关键特性之checkpoint

一、日常关注的问题

MySQL技术:InnoDB存储引擎关键特性之checkpoint_第1张图片

1、我们的日志生成速度?

  1、每天生成多少日志、产生多少redo log

mysql> show global status like 'Innodb_os_log_written';
+-----------------------+--------+
| Variable_name         | Value  |
+-----------------------+--------+
| Innodb_os_log_written | 107008 |
+-----------------------+--------+
1 row in set (0.01 sec)

  2、如果redolog量大,需要修改如下参数,增加logfile的大小和组数

mysql> show variables like 'i%log_file%';
+---------------------------+----------+
| Variable_name             | Value    |
+---------------------------+----------+
| innodb_log_file_size      | 50331648 |
| innodb_log_files_in_group | 2        |
+---------------------------+----------+
2 rows in set (0.00 sec)

2、日志写入速度?

  Log buffer有没有满、满的话为什么满

mysql> show variables like 'i%log_buffer%';
+------------------------+----------+
| Variable_name          | Value    |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
1 row in set (0.01 sec)

mysql> show global status like '%log_pending%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Innodb_os_log_pending_fsyncs | 0     |
| Innodb_os_log_pending_writes | 0     |
+------------------------------+-------+
2 rows in set (0.01 sec)

3、脏页的写入速度?

  1、Log buffer满了会hang住

  2、Logfile满了不能被覆盖也会hang住

  3、如果脏页写入速度慢的话,logfile满了也不能被覆盖,系统容易hang住,log buffer如果满了的话也容易hang住。

4、数据库启动时间是多少?

  启动时,默认是要先恢复脏页。当然,能通过参数innodb_force_recovery启动控制。

  如果innodb_buffer_pool很大,32G,极端情况可能有32G的脏页,这个时候如果崩了,恢复的话需要恢复这32G的脏页,时间非常长。



二、日志点分析

  通过show engine innodb status\G解释一下LOG相关的四行参数的值:

Log sequence number 143942609---LSN:日志序列号(1)  

  //字节,日志生成的最新位置,最新位置出现在log buffer中

Log flushed up to   143942609---(2)  

  //字节,日志已经写入到log file的位置,1-2=log buffer日志量,最好是<=1M

Pages flushed up to 143942609---(3)  

  //字节,脏页的数量(日志字节数来衡量),2-3=脏页的数量(日志字节为单位)

Last checkpoint at  143942600---(4)  

  //字节,共享表空间上的日志记录点,最后一次检查点,及崩溃恢复时指定的起点,3-4就是崩溃恢复多跑的日志,值越大说明需要提升checkpoint的跟进速度

MySQL技术:InnoDB存储引擎关键特性之checkpoint_第2张图片



三、checkpoint

  检查点,表示脏页写入到磁盘的时候,也就意味着脏数据的写入。

1、checkpoint的目的

  1、缩短数据库的恢复时间

        当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘。数据库只需对Checkpoint后的重做日志进行恢复,这样就大大缩短了恢复的时间。

  2、buffer pool空间不够用时,将脏页刷新到磁盘

        当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。

  3、redo log不可用时,刷新脏页

        当重做日志出现不可用时,因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让其无限增大的,重做日志可以被重用的部分是指这些重做日志已经不再需要,当数据库发生宕机时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。如果重做日志还需要使用,那么必须强制Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。

        对于InnoDB存储引擎而言,是通过LSN(Log Sequence Number)来标记版本的。

        LSN是8字节的数字,每个页有LSN,重做日志中也有LSN,Checkpoint也有LSN。可以通过命令SHOW ENGINE INNODB STATUS来观察:

mysql> show engine innodb status \G
 
---
LOG
---
Log sequence number 34778380870
Log flushed up to   34778380870
Last checkpoint at  34778380870
0 pending log writes, 0 pending chkp writes
54020151 log i /o 's done, 0.92 log i/o' s /second

        Checkpoint发生的时间、条件及脏页的选择等都非常复杂。而Checkpoint所做的事情无外乎是将缓冲池中的脏页刷回到磁盘,不同之处在于每次刷新多少页到磁盘,每次从哪里取脏页,以及什么时间触发Checkpoint。

2、检查点分类

  1、sharp checkpoint:完全检查点,数据库正常关闭时,会触发把所有的脏页都写入到磁盘上(这时候logfile的日志就没用了,脏页已经写到磁盘上了)。

    1、完全检查点,发生在数据库正常关闭的时候。

    2、在数据库在运行时不会使用sharp checkpoint,在引擎内部使用fuzzy checkpoint,即只刷新一部分脏页,而不是刷新所有的脏页回磁盘。

  2、fuzzy checkpoint:模糊检查点,部分页写入磁盘。

    1、发生在数据库正常运行期间。

    2、模糊检查点,不是sharp的就是模糊检查点(4种):master thread checkpoint、flush_lru_list checkpoint、async/sync flush checkpoint、dirty page too much checkpoint。



四、fuzzy checkpoint发生的4个条件

  模糊检查点的发生,也就是脏页写入磁盘的情况。



1、master thread checkpoint

  差不多以每秒或每十秒的速度从缓冲池的脏页列表中刷新一定比例的页回磁盘,这个过程是异步的,不会阻塞用户查询。

  1、周期性,读取flush list,找到脏页,写入磁盘

  2、写入的量比较小

  3、异步,不影响业务

mysql> show variables like '%io_cap%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_io_capacity     | 200   |
| innodb_io_capacity_max | 2000  |
+------------------------+-------+
2 rows in set (0.01 sec)

  4、通过innodb_io_capacity能力告知进行刷盘控制

    通过innodb的io能力告知,控制对flush list刷脏页数量,innodb_io_capacity越高,每次刷盘写入脏页数越多;

    如果脏页数量过多,刷盘速度很慢,在io能力允许的情况下,调高innodb_io_capacity值,让多刷脏页。



2、flush_lru_list checkpoint

  MySQL会保证,保证里面有多少可用的空闲页,在innodb 1.1.x版本之前,需要检查在用户查询线程中是否有足够的可用空间(差不多100个空闲页),显然这会阻塞用户线程,如果没有100个可用空闲页,那么innodb会将lru列表尾端的页移除,如果这些页中有脏页,那么需要进行checkpoint。

        Innodb 1.2(5.6)版本之后把它单独放到一个线程Page Cleaner Thread中进行,用户可以通过参数innodb_lru_scan_depth控制lru列表中可用页的数量,默认是1024。

  读取lru list,找到脏页,写入磁盘。

mysql> show variables like '%lru%depth';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_lru_scan_depth | 1024  |
+-----------------------+-------+
1 row in set (0.01 sec)

  此情况下触发,默认扫描1024个lru冷端数据页,将脏页写入磁盘(有10个就刷10,有100个就刷100个……)   



3、async/sync flush checkpoint

        指的是重做日志文件不可用的情况,这时需要强制将一些页刷新回磁盘,而此时脏页是从脏页列表中选取的。若将已经写入到重做日志的LSN记为redo_lsn,将已经刷新回磁盘最新页的LSN记为checkpoint_lsn,则可定义:

        checkpoint_age = redo_lsn - checkpoint_lsn

        再定义以下的变量:

        async_water_mark = 75% * total_redo_log_file_size

        sync_water_mark = 90% * total_redo_log_file_size

        若每个重做日志文件的大小为1GB,并且定义了两个重做日志文件,则重做日志文件的总大小为2GB。那么async_water_mark=1.5GB,sync_water_mark=1.8GB。则:

        当checkpoint_age

        当async_water_mark

        checkpoint_age>sync_water_mark这种情况一般很少发生,除非设置的重做日志文件太小,并且在进行类似LOAD DATA的BULK INSERT操作。此时触发Sync Flush操作,从Flush列表中刷新足够的脏页回磁盘,使得刷新后满足checkpoint_age

  Async/Sync Flush Checkpoint是为了保证重做日志的循环使用的可用性。在InnoDB 1.2.x版本之前,Async Flush Checkpoint会阻塞发现问题的用户查询线程,而Sync Flush Checkpoint会阻塞所有的用户查询线程,并且等待脏页刷新完成。从InnoDB 1.2.x版本开始——也就是MySQL 5.6版本,这部分的刷新操作同样放入到了单独的Page Cleaner Thread中,故不会阻塞用户查询线程。



4、dirty page too much checkpoint

  即脏页的数量太多,导致InnoDB存储引擎强制进行Checkpoint。其目的总的来说还是为了保证缓冲池中有足够可用的页。其可由参数innodb_max_dirty_pages_pct控制。

  1、脏页监控,关注点

mysql> show global status like 'Innodb_buffer_pool_pages%t%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| Innodb_buffer_pool_pages_data  | 2964  |
| Innodb_buffer_pool_pages_dirty | 0     |
| Innodb_buffer_pool_pages_total | 8191  |
+--------------------------------+-------+
3 rows in set (0.00 sec)

mysql> show global status like '%wait_free';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Innodb_buffer_pool_wait_free | 0     |
+------------------------------+-------+
1 row in set (0.00 sec)

    1、Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total:表示脏页在buffer 的占比

    2、Innodb_buffer_pool_wait_free:如果>0,说明出现性能负载,buffer pool中没有干净可用块

  2、脏页控制参数

mysql> show variables like '%dirty%pct%';
+--------------------------------+-----------+
| Variable_name                  | Value     |
+--------------------------------+-----------+
| innodb_max_dirty_pages_pct     | 75.000000 |
| innodb_max_dirty_pages_pct_lwm | 0.000000  |
+--------------------------------+-----------+
2 rows in set (0.01 sec)

    1、默认是脏页占比75%的时候,就会触发刷盘,将脏页写入磁盘,腾出内存空间。建议不调,调太低的话,io压力就会很大,但是崩溃恢复就很快;

    2、lwm:low water mark低水位线,刷盘到该低水位线就不写脏页了,0也就是不限制。

注意:上面在调整的时候,要关注系统的写性能iostat -x。

5、Checkpoint机制

在Innodb事务日志中,采用了Fuzzy Checkpoint,Innodb每次取最老的modified page(last checkpoint)对应的LSN,再将此脏页的LSN作为Checkpoint点记录到日志文件,意思就是“此LSN之前的LSN对应的日志和数据都已经flush到redo log

当mysql crash的时候,Innodb扫描redo log,从last checkpoint开始apply redo log到buffer pool,直到last checkpoint对应的LSN等于Log flushed up to对应的LSN,则恢复完成

那么具体是怎么恢复的呢?

MySQL技术:InnoDB存储引擎关键特性之checkpoint_第3张图片

如上图所示,Innodb的一条事务日志共经历4个阶段:

  • 创建阶段:事务创建一条日志;

  • 日志刷盘:日志写入到磁盘上的日志文件;

  • 数据刷盘:日志对应的脏页数据写入到磁盘上的数据文件;

  • 写CKP:日志被当作Checkpoint写入日志文件;

对应这4个阶段,系统记录了4个日志相关的信息,用于其它各种处理使用:

  • Log sequence number(LSN1):当前系统LSN最大值,新的事务日志LSN将在此基础上生成(LSN1+新日志的大小);

  • Log flushed up to(LSN2):当前已经写入日志文件的LSN;

  • Oldest modified data log(LSN3):当前最旧的脏页数据对应的LSN,写Checkpoint的时候直接将此LSN写入到日志文件;

  • Last checkpoint at(LSN4):当前已经写入Checkpoint的LSN;

对于系统来说,以上4个LSN是递减的,即: LSN1>=LSN2>=LSN3>=LSN4.

具体的样例如下(使用show innodb status \G命令查看,Oldest modified data log没有显示):

LOG
---
Log sequence number 34822137537
Log flushed up to   34822137537
Last checkpoint at  34822133028
0 pending log writes, 0 pending chkp writes
54189288 log i /o 's done, 3.00 log i/o' s /second  

四、日志保护机制 

mysql crash的时候,Innodb有日志刷盘机制,可以通过innodb_flush_log_at_trx_commit参数进行控制,这里说的是如何防止日志覆盖导致日志丢失

Innodb的checkpoint和redo log有哪些紧密关系?有几上名词需要解释一下:

  • Ckp age(动态移动): 最老的dirty page还没有flush到数据文件,即没有做last checkpoint的范围

  • Buf age(动态移动): modified page information没有写到log中,但已在log buffer

  • Buf async(固定点): 日志空间大小的7/8,当buf age移动到Buf async点时,强制把没有写到log中的modified page information开始写入到log中,不阻塞事务

  • Buf sync(固定点): 日志空间大小的15/16,当写入很大的,buf age移动非常快,一下子到buf sync的点,阻塞事务,强制把modified page information开始写入到log中。如果不阻塞事务,未做last checkpoint的redo log存在覆盖危险

  • Ckp async(固定点): 日志空间大小的31/32,当ckp age到达ckp async,强制做last checkpoint,不阻塞事务

  • Ckp sync(固定点):日志空间大小,当ckp age到达ckp sync,强制做last checkpoint,阻塞事务,存在redo log覆盖的危险

接下来分析4种情况

  • 如果buf age在buf async和buf sync之间

  • 如果buf age在buf sync之后(当然这种情况是不存在,mysql有保护机制)

  • 如果ckp age在ckp async和ckp sync之间(这种情况是不存在)

  • 如果ckp age在ckp sync之后(这种情况是不存在)

第一种情况:

当写入量巨大时,buf age移动到buf async和buf sync之间,触发写出到log中,mysql把尽量多的log写出,如果写入量减慢,buf age又移回到“图一”状态。如果写入量大于flush log的速度,buf age最终会和buf sync重叠,这时所有的事务都被阻塞,强制将2*(Buf age-Buf async)的脏页刷盘,这时IO会比较繁忙。

第二种情况:

当然这种情况是不可能出现,因为如果出现,redo log存在覆盖的可能,数据就会丢失。buf age会越过log size,buf age的大小可能就超过log size,如果要刷buf age,那么整个log size都不够容纳所有的buf age。


第三种和第四种情况不存在分析:

ckp age始终位于buf age的后面(左边),因为ckp age是last checkpoint点,总是追赶buf age(将尽可能多的modified page flush到磁盘),所以buf age肯定是先到达到buf sync。

ckp async及ckp sync存在意义?

mysql中page cache也存在high water及low water,当dirty page触到low water时,os是开始flush dirty page到磁盘,到high water时,会阻塞一切动作,os会疯狂的flush dirty page,磁盘会很忙,存在IO Storm


参考链接:MySQL checkpoint深入分析 - GeaoZhang - 博客园

参考链接:关于checkpoint机制_liu0808的专栏-CSDN博客

你可能感兴趣的:(Mysql,mysql,数据库,mongodb)