WAL机制: Write-Ahead Logging, 先写日志,再写磁盘。 当有一条记录需要更新的时候,InnoDB引擎会先把记录写到redo log里面,并更新内存,这个时候更新计算完成了。InnoDB引擎会在在系统空闲的时候,将这个操作记录更新到磁盘里。

WAL机制的益处: redo log 和 binlog 都是顺序写,磁盘的顺序写比随机写速度要快,可以大幅度降低磁盘的 IOPS 消耗。

数据库的flush操作就是将内存中的数据更新到磁盘中并将redo log的checkpoint前推,保持磁盘和内存数据一致性。

脏页: 当磁盘数据页和内存数据页的内容不一样的时候。

干净页: 当内存数据写入磁盘,磁盘数据页和内存数据页一样的时候。

11.1 什么情况会触发数据库的flush操作?

  1. redo log写满:这种情况的flush会导致所有更新操作暂停,将checkpiont前推,将前推过程中的日志对应的脏页全部写入磁盘中,原位置到现在停止位置就是新的可写入位置。
  2. 内存不足:内存无空闲数据页,需要通过淘汰算法选择出相应数据页,再判断淘汰的数据页是否为脏页来选择下一次操作。
  3. MySQL空闲时候:合理利用时间
  4. MySQL关闭之前:flush到磁盘,下次再启动数据库就不需要重新根据日志推导。

上面四种场景的性能分析: 对第三种,第四种情况不给予分析,情况数据正常操作。

第一种情况: redo log写满,要flush脏页,在flush期间,所有的更新业务暂停,对性能来说是大打击。

第二种情况: 内存不够,需要刷新脏页到磁盘中。内存分为三种,已使用脏页,已使用干净页,未使用页。当需要申请一个内存页面时,内存满了,需要先淘汰页面,使用相应的淘汰算法选择页面,例如最长时间未使用算法(LRU),淘汰的页面也分两种情况:①干净页:直接释放使用;②脏页:flush到磁盘中变成干净页而后释放使用。

以下两种情况会明显影响性能:

  1. redo log写满,更新操作停住进行flush操作。
  2. 一个更新操作涉及多个脏页flush。

想要控制这两个我们需要控制脏页的比例redo log的写盘速度

11.2 InnoDB 刷脏页的控制策略

redo log的写盘速度控制:

通过参数 innodb_io_capacity 来设置MySQL全力刷脏页的速度,建议设置为磁盘的IOPS,磁盘的IOPS可以使用fio工具来获得→fio工具的使用

脏页的比例:

通过参数 innodb_max_dirty_pages_pct 设置脏页比例上限,默认值是 75%。

MySQL通过设置脏页比来,来计算出redo log应该的写盘速度,示意图如下:

在这里插入图片描述

MySQL在flush内存中脏页时,有一个策略叫做脏页连坐,如果当前flush的脏页的邻居也是脏页,也会连同一起flush,直到碰见一个干净页的邻居。我们也可以通过参数 innodb_flush_neighbors 设置,1表示开启,0表示不开启。

在 MySQL 8.0 中,innodb_flush_neighbors 参数的默认值已经是 0 。

练习问题:

  1. WAL机制?脏页和干净页的定义?
  2. 触发数据库flush操作的四种场景?分析其中关键场景?
  3. 缓存池中内存的三种状态?哪种flush会比较影响性能?
  4. InnoDB控制脏页策略?参数innodb_io_capacity 和参数innodb_max_dirty_pages_pct ?
  5. 参数innodb_flush_neighbors?

更多推荐