共计 3003 个字符,预计需要花费 8 分钟才能阅读完成。
1,checkpoint 产生的背景
数据库在发生增删查改操作的时候,都是先在 buffer pool 中完成的,为了提高事物操作的效率,buffer pool 中修改之后的数据,并没有立即写入到磁盘,这有可能会导致内存中数据与磁盘中的数据产生不一致的情况。
事物要求之一是持久性(Durability),buffer pool 与磁盘数据的不一致性的情况下发生故障,可能会导致数据无法持久化。
为了防止在内存中修改但尚未写入到磁盘的数据,在发生故障重启数据之后产生事物未持久化的情况,是通过日志 (redo log) 先行的方式来保证的。
redo log 可以在故障重启之后实现“重做”,保证了事物的持久化的特性,但是 redo log 空间不可能无限制扩大,对于内存中已修改但尚未提交到磁盘的数据,也即脏页,也需要写入磁盘。
对于内存中的脏页,什么时候,什么情况下,将多少脏页写入磁盘,是由多方面因素决定的。
checkpoint 的工作之一,就是对于内存中的脏页,在一定条件下将脏页刷新到磁盘。
2,checkpoint 的分类
按照 checkpoint 刷新的方式,MySQL 中的 checkpoint 分为两种,也即 sharp checkpoint 和 fuzzy checkpoint。
sharp checkpoint:在关闭数据库的时候,将 buffer pool 中的脏页全部刷新到磁盘中。
fuzzy checkpoint:数据库正常运行时,在不同的时机,将部分脏页写入磁盘,进刷新部分脏页到磁盘,也是为了避免一次刷新全部的脏页造成的性能问题。
3,checkpoint 发生的时机
checkpoint 都是将 buffer pool 中的脏页刷新到磁盘,但是在不同的情况下,checkpoint 会被以不同的方式触发,同时写入到磁盘的脏页的数量也不同。
3.1,Master Thread checkpoint
在 Master Thread 中,会以每秒或者每 10 秒一次的频率,将部分脏页从内存中刷新到磁盘,这个过程是异步的。正常的用户线程对数据的操作不会被阻塞。
3.2,FLUSH_LRU_LIST checkpoint
FLUSH_LRU_LIST checkpoint 是在单独的 page cleaner 线程中执行的。
MySQL 对缓存的管理是通过 buffer pool 中的 LRU 列表实现的,LRU 空闲列表中要保留一定数量的空闲页面,来保证 buffer pool 中有足够的空闲页面来相应外界对数据库的请求。
当这个空间页面数量不足的时候,发生 FLUSH_LRU_LIST checkpoint。
空闲页的数量由 innodb_lru_scan_depth 参数表来控制的,因此在空闲列表页面数量少于配置的值的时候,会发生 checkpoint,剔除部分 LRU 列表尾端的页面。
3.3,Async/Sync Flush checkpoint
Async/Sync Flush checkpoint 是在单独的 page cleaner 线程中执行的。
Async/Sync Flush checkpoint 发生在重做日志不可用的时候,将 buffer pool 中的一部分脏页刷新到磁盘中,在脏页写入磁盘之后,事物对应的重做日志也就可以释放了。
关于 redo_log 文件的的大小,可以通过 innodb_log_file_size 来配置。
对于是执行 Async Flush checkpoint 还是 Sync Flush checkpoint,由 checkpoint_age 以及 async_water_mark 和 sync_water_mark 来决定。
定义:
checkpoint_age = redo_lsn-checkpoint_lsn,也即 checkpoint_age 等于最新的 lsn 减去已经刷新到磁盘的 lsn 的值
async_water_mark = 75%*innodb_log_file_size
sync_water_mark = 90%*innodb_log_file_size
1)当 checkpoint_age<sync_water_mark 的时候,无需执行 Flush checkpoint。也就说,redo log 剩余空间超过 25% 的时候,无需执行 Async/Sync Flush checkpoint。
2)当 async_water_mark<checkpoint_age<sync_water_mark 的时候,执行 Async Flush checkpoint,也就说,redo log 剩余空间不足 25%,但是大于 10% 的时候,执行 Async Flush checkpoint,刷新到满足条件 1
3)当 checkpoint_age>sync_water_mark 的时候,执行 sync Flush checkpoint。也就说,redo log 剩余空间不足 10% 的时候,执行 Sync Flush checkpoint,刷新到满足条件 1。
在 mysql 5.6 之后,不管是 Async Flush checkpoint 还是 Sync Flush checkpoint,都不会阻塞用户的查询进程。
个人认为:
由于磁盘是一种相对较慢的存储设备,内存与磁盘的交互是一个相对较慢的过程
由于 innodb_log_file_size 定义的是一个相对较大的值,正常情况下,由前面两种 checkpoint 刷新脏页到磁盘,在前面两种 checkpoint 刷新脏页到磁盘之后,脏页对应的 redo log 空间随即释放,一般不会发生 Async/Sync Flush checkpoint。同时也要意识到,为了避免频繁低发生 Async/Sync Flush checkpoint,也应该将 innodb_log_file_size 配置的相对较大一些。
3.4,Dirty Page too much Checkpoint
Dirty Page too much Checkpoint 是在 Master Thread 线程中每秒一次的频率实现的。
Dirty Page too much 意味着 buffer pool 中的脏页过多,执行 checkpoint 脏页刷入磁盘,保证 buffer pool 中有足够的可用页面。
Dirty Page 由 innodb_max_dirty_pages_pct 配置,innodb_max_dirty_pages_pct 的默认值在 innodb 1.0 之前是 90%,之后是 75%。
总结:
MySQL 数据库(当然其他关系数据也有类似的机制),为了提高事物操作的效率,在事物提交之后并不会立即将修改后的数据写入磁盘,而是通过日志先行(write log ahead)的方式保证事物的持久性。
对于将事物修改的数据页面,也即脏页,通过异步的方式刷新到磁盘中,checkpoint 正是实现这种异步刷新脏页到磁盘的实施者。
不同的情况下,会发生不同的 checkpoint,将不同数量的脏页刷新到磁盘,从而到达管理内存(第 1,2,4 种 checkpoint)和 redo log 可用空间(第 3 种 checkpoint)的目的。
参考:《MySQL 技术内幕 Innodb 存储引擎》PDF 下载见 http://www.linuxidc.com/Linux/2013-06/86413.htm
本文永久更新链接地址:http://www.linuxidc.com/Linux/2018-01/150615.htm