导读:
最近又拿出了尘封已久的kindle,开始第三遍看姜老师的《MySQL技术内幕》,每次看都有不同的理解,今天看了checkpoint部分加上自己的理解后整理了这篇文章。
Checkpoint的作用
在说checkpoint的作用之前,我们假设如果没有checkpoint。MySQL一直写数据,一直刷redo,当前的lsn一直增长,此时如果MySQL Crash了,那么MySQL在重新启动以后,不知道要从哪个位点开始进行redo重放,那就不得不从头开始应用redo,整个过程会持续非常长。而如果有了checkpoint,保证checkpoint之前的脏页都刷新回磁盘了,那么崩溃恢复直接从checkpoint的点开始应用redo即可。
那么有哪些情况会触发checkpoint呢?大致有以下这么几种情况
master thread固定频率checkpoint
缓冲池不够用了,LRU list淘汰page,淘汰的page属于脏页,需要强制checkpoint
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差不多每秒都会以下几件事情:
flush redo
checkpoint
merge change buffer
flush dirty page
clean table cache
每10秒会做以下几件事情:
flush redo
checkpoint
merge change buffer
flush dirty page
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呢?
这里贴一段源码
checkpoint_age = log->lsn - log->last_checkpoint_lsn;
bool checkpoint_sync;
bool do_checkpoint;
if (checkpoint_age > log->max_checkpoint_age) {
/* A checkpoint is urgent: we do it synchronously */
checkpoint_sync = true;
do_checkpoint = true;
} else if (checkpoint_age > log->max_checkpoint_age_async) {
/* A checkpoint is not urgent: do it asynchronously */
do_checkpoint = true;
checkpoint_sync = false;
log->check_flush_or_checkpoint = false;
} else {
do_checkpoint = false;
checkpoint_sync = false;
log->check_flush_or_checkpoint = false;
}
复制
从源码中就可以看出:
checkpoint age = 当前lsn - 上一次checkpoint lsn位置
当checkpoint age >
max_checkpoint_age
就进行sync checkpoint即同步刷新当checkpoint age >
max_checkpoint_age_async
就进行async checkpoint即异步刷新
这个 max_checkpoint
和 max_checkpoint_age_async
的计算在函数 log_calc_max_ages
中完成,精简如下
/* Add extra safety */
smallest_capacity = smallest_capacity - smallest_capacity / 10;
//smallest_capacity的计算方法是(单个redo logfile- 头部大小)* redo log组数
/* For each OS thread we must reserve so much free space in the
smallest log group that it can accommodate the log entries produced
by single query steps: running out of free log space is a serious
system error which requires rebooting the database. */
free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)
+ LOG_CHECKPOINT_EXTRA_FREE;
if (free >= smallest_capacity / 2) {
success = false;
goto failure;
} else {
margin = smallest_capacity - free;
}
margin = margin - margin / 10; /* Add still some extra safety */
log_sys->log_group_capacity = smallest_capacity;
log_sys->max_modified_age_async = margin
- margin / LOG_POOL_PREFLUSH_RATIO_ASYNC;
log_sys->max_modified_age_sync = margin
- margin / LOG_POOL_PREFLUSH_RATIO_SYNC;
log_sys->max_checkpoint_age_async = margin - margin
/ LOG_POOL_CHECKPOINT_RATIO_ASYNC;
log_sys->max_checkpoint_age = margin;
//其中几个常量定义如下:
LOG_POOL_CHECKPOINT_RATIO_ASYNC 32
LOG_POOL_PREFLUSH_RATIO_SYNC 16
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等。因此也不建议设置过大,需要根据实际的压测情况进行设置,如果设置过大,在错误日志中可能出现如下告警:
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源码时会讲解)