暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

InnoDB Checkpoint读书笔记

mysql code tracer 2021-04-25
2340

导读:

最近又拿出了尘封已久的kindle,开始第三遍看姜老师的《MySQL技术内幕》,每次看都有不同的理解,今天看了checkpoint部分加上自己的理解后整理了这篇文章。

Checkpoint的作用

在说checkpoint的作用之前,我们假设如果没有checkpoint。MySQL一直写数据,一直刷redo,当前的lsn一直增长,此时如果MySQL Crash了,那么MySQL在重新启动以后,不知道要从哪个位点开始进行redo重放,那就不得不从头开始应用redo,整个过程会持续非常长。而如果有了checkpoint,保证checkpoint之前的脏页都刷新回磁盘了,那么崩溃恢复直接从checkpoint的点开始应用redo即可。

那么有哪些情况会触发checkpoint呢?大致有以下这么几种情况

  1. master thread固定频率checkpoint

  2. 缓冲池不够用了,LRU list淘汰page,淘汰的page属于脏页,需要强制checkpoint

  3. redo不够用了,强制checkpoint以释放redo空间被新事务覆盖

Checkpoint的分类

MySQL的checkpoint可以分为如下几类:

  • sharp checkpoint

  • fuzzy checkpoint

sharp checkpoint

当关闭innodbfastshutdown时,MySQL实例进行关闭,需要进行sharp checkpoint,即保证所有的脏页刷新到磁盘。sharp checkpoint一般使用在实例进行升级等场景,确保MySQL足够安全。

fuzzy checkpoint

  • Master Thread Checkpoint

  • FLUSH LRU LIST Checkpoint

  • Async/Sync Flush Checkpoint

  • Drity Page too much Checkpoint

Master Thread Checkpoint

Master Thread差不多每秒都会以下几件事情:

  1. flush redo

  2. checkpoint

  3. merge change buffer

  4. flush dirty page

  5. clean table cache

每10秒会做以下几件事情:

  1. flush redo

  2. checkpoint

  3. merge change buffer

  4. flush dirty page

  5. purge undo

可以看到Master Thread差不多每秒和每十秒都会进行checkpoint,从innodb buffer pool的脏页列表刷新一定比例的脏页回磁盘,这个过程是异步的,用户查询不会阻塞。

FLUSH_LRU_LISTCheckpoint

InnoDB引擎需要保证LRU list中有一定空闲的page可供使用,这个空闲的页数由参数 innodb_lru_scan_depth
控制,默认值为1024。当LRU list中的空闲页数不够的时候,InnoDB会将LRU列表尾部的page移除,而恰好要移除的page属于dirty page的时候,需要进行checkpoint。

Async/Sync Flush Checkpoint

当redo log不够的时候,InnoDB将会进行Async Flush Checkpoint或者Sync Flush Checkpoint,那么什么时候会进行Async Flush Checkpoint什么时候会进行Sync Flush Checkpoint呢?

这里贴一段源码

  1. checkpoint_age = log->lsn - log->last_checkpoint_lsn;

  2. bool checkpoint_sync;

  3. bool do_checkpoint;

  4. if (checkpoint_age > log->max_checkpoint_age) {

  5. /* A checkpoint is urgent: we do it synchronously */

  6. checkpoint_sync = true;

  7. do_checkpoint = true;

  8. } else if (checkpoint_age > log->max_checkpoint_age_async) {

  9. /* A checkpoint is not urgent: do it asynchronously */

  10. do_checkpoint = true;

  11. checkpoint_sync = false;

  12. log->check_flush_or_checkpoint = false;

  13. } else {

  14. do_checkpoint = false;

  15. checkpoint_sync = false;

  16. log->check_flush_or_checkpoint = false;

  17. }

复制

从源码中就可以看出:

  1. checkpoint age = 当前lsn - 上一次checkpoint lsn位置

  2. 当checkpoint age > max_checkpoint_age
    就进行sync checkpoint即同步刷新

  3. 当checkpoint age > max_checkpoint_age_async
    就进行async checkpoint即异步刷新

这个 max_checkpoint
max_checkpoint_age_async
的计算在函数 log_calc_max_ages
中完成,精简如下

  1. /* Add extra safety */

  2. smallest_capacity = smallest_capacity - smallest_capacity / 10;

  3. //smallest_capacity的计算方法是(单个redo logfile- 头部大小)* redo log组数

  4. /* For each OS thread we must reserve so much free space in the

  5. smallest log group that it can accommodate the log entries produced

  6. by single query steps: running out of free log space is a serious

  7. system error which requires rebooting the database. */

  8. free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)

  9. + LOG_CHECKPOINT_EXTRA_FREE;

  10. if (free >= smallest_capacity / 2) {

  11. success = false;

  12. goto failure;

  13. } else {

  14. margin = smallest_capacity - free;

  15. }

  16. margin = margin - margin / 10; /* Add still some extra safety */

  17. log_sys->log_group_capacity = smallest_capacity;

  18. log_sys->max_modified_age_async = margin

  19. - margin / LOG_POOL_PREFLUSH_RATIO_ASYNC;

  20. log_sys->max_modified_age_sync = margin

  21. - margin / LOG_POOL_PREFLUSH_RATIO_SYNC;

  22. log_sys->max_checkpoint_age_async = margin - margin

  23. / LOG_POOL_CHECKPOINT_RATIO_ASYNC;

  24. log_sys->max_checkpoint_age = margin;

  25. //其中几个常量定义如下:

  26. LOG_POOL_CHECKPOINT_RATIO_ASYNC 32

  27. LOG_POOL_PREFLUSH_RATIO_SYNC 16

  28. LOG_POOL_PREFLUSH_RATIO_ASYNC 8

复制

margin近似认为是Innodb系统可用的日志空间的9/10;

  • 日志空间消耗超过7/8时,进行异步Flush Redo

  • 日志空间消耗超过15/16时,进行同步Flush Redo

  • 日志空间消耗超过31/32时,进行异步Checkpoint

  • 日志消耗达到margin时,进行同步Checkpoint

计算 smallest_capacity
和margin时都进行了部分空闲的预留,目的也是为了预留一些系统资源,避免因为堆积导致了系统hang住的情况。

Drity Page too much Checkpoint

当InnoDB buffer pool中的脏页达到一定比例的时候,也会触发checkpoint,这个比例由参数 innodb_max_dirty_pages_pct
控制,5.7下默认是75,即脏页超过总page 的75%时,InnoDB会强制进行checkpoint,刷新部分脏页到磁盘,生产上建议不要过大,建议50即可。

关于 innodb_io_capacity
和 innodb_io_capacity_max

这两个参数定义了innodb对于io能力的评估,这两个参数会影响到脏页刷新、checkpoint、change buffer merge等。因此也不建议设置过大,需要根据实际的压测情况进行设置,如果设置过大,在错误日志中可能出现如下告警:

  1. 2018-10-20T07:11:07.819365+08:00 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 5529ms. The settings might not be optimal. (flushed=133 and evicted=0, during the time.)

复制

另外需要注意的是,如果设置了 innodb_flush_sync
参数,那么会忽略参数 innodb_io_capacity
innodb_io_capacity_max

总结

  • 本文讲解了checkpoint的作用及分类

  • 需要理解checkpoint触发的时机,并及时做好监控,尤其是checkpoint age,避免MySQL由于checkpoint导致性能下降

  • 关于 innodb_io_capacity
    和 innodb_io_capacity_max
    两个参数建议不要设置过大,也不要设置太小,根据实际的压测情况来设置

  • crash recovery起来以后,获取到last checkpoint是从 ib_logfile0
    的头部获取(这点后续剖析crash recovery源码时会讲解)

文章转载自mysql code tracer,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论