《MySQL45讲》读书笔记(三):内存数据刷盘机制
此⽂为极客时间:MySQL实战45讲的12节的学习笔记
⼀、mysql 的刷盘机制
⽽之前提到过,mysql 使⽤了 WAL 技术,即更新的时候先更新内存中的数据,然后必要的时候再将内存中的数据刷⼊磁盘。我们把内存中这些被修改过,跟磁盘中的数据页不⼀致的数据页称为脏页。
其中,有四种情况会触发脏页的刷盘:
1. redo log 可写空间满了。
2. 内存满了,需要淘汰的数据页恰好是脏页。
3. 系统不繁忙的时候。
4. 关闭数据库的时候。
其中,第三种情况不会为系统带来过多影响的,第四中情况下不会在乎为系统带来的影响。所以我们只需要关注第⼀和第⼆种情况:
对于第⼆种情况,由于 mysql 的更新需要先写⽇志,所以当⽇志满了的情况下,所有的更新都会停⽌,⼀直到刷完盘⽇志腾出了空间为⽌;
⽽对于第⼆种情况,当查询的数据在内存中的数据页没有的时候,就需要淘汰旧页释放内存以读⼊新页,所以当⼀次查询导致需要淘汰的脏页过多的时候,就需要先等待较长的刷盘时间,然后才能获取响应。
为了避免上述两种情况,必须要控制脏页在内存中的⽐例。
⼆、刷脏页的控制策略
⾸先,我们必须要知道主机磁盘的写⼊能⼒有多强,这样 innodb 才可以知道它刷脏页的速度最快应该是多快。
我们可以通过设置innodb_io_capacity这个参数来告诉 innodb 磁盘的写⼊速度。这个参数的值不宜过⼩,因为这会导致 innodb 错误的估计刷盘速度,最后导致刷脏页的速度跟不上脏页⽣成的速度。
innodb_io_capacity规定了刷脏页速度的极限,但是实际上磁盘不可能只服务这么⼀个功能,所以还需要参考 redo log 的刷盘速度和允许的内存中的脏页⽐例。
参数innodb_max_dirty_pages_pct是脏页⽐例上限,默认值是 75%。innodb 会根据当前的脏页⽐例(假设为 M),算出⼀个范围在 0到 100 之间的数字,这个公式是F1(M)。
⽽每次写⼊ redo log 的写⼊点 wp 都会有⼀个序号,innodb 会根据这个序号和上⼀次清理⽇志的界限 cp 之间的差值——我们假设为 N——计算得到⼀个范围在 0 到 100 之间的数字,这个公式是F2(N)
根据上述算得的F1(M)和F2(N)两个值,取其中较⼤的值记为 R,之后引擎就可以按照innodb_io_capacity定义的能⼒乘以 R% 来控制刷脏页的速度。
这⼀整个流程对应的图⽚是这样的:
所以,我们需要关注内存中的脏页⽐例,让它尽量不要到75%,并且合理的设置innodb_io_capacity参数。
其中,针对脏页的⽐例,我们可以通过Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total去设置。
另外,由于 mysql 存在这样⼀个机制:如果要刷盘的脏页相邻的数据页恰好也是脏页,就⼀起写⼊磁盘,如果邻居的邻居也是如此。在机械硬盘时代这个策略可以减少随机IO,但是如果使⽤固态硬盘的话随机IO的性能往往⽐较⾼,所以使⽤这个策略反⽽拖累了查询性能。因此可以通过innodb_flush_neighbors关闭这个“连坐”的策略。
三、总结
innodb 有四种情况会触发脏页的刷盘:
redo log 可写空间满了;
内存满了,需要淘汰的数据页恰好是脏页;
系统不繁忙的时候;
关闭数据库的时候。mysql下载哪个盘
innodb 通过的刷盘速度通过类似这样的公式计算:
innodb_io_capacity * Max( F(innodb_max_dirty_pages_pct), F(redo log的wp - redo log的cp) )
其中,innodb_io_capacity表⽰磁盘的最⼤IO能⼒;innodb_max_dirty_pages_pct表⽰允许脏页在内存中的占⽐,默认值为
75%;
当使⽤固态硬盘的时候,可以设置innodb_flush_neighbors关闭默认的刷新相邻脏页的策略。