InnoDB 缓冲池LRU策略及关键特性

内存

缓冲池

缓冲池简单来说就是一块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。在数据库中读取页的操作,首先将从磁盘读取的页存放在缓冲池中,这个过程称为将页 “FIX” 在缓冲池中。下一次再读取相同的页时,首先判断该页是否在缓冲中。若在则命中,否则读取磁盘上的页。

对于数据库中的页的修改,首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上,页冲缓冲池刷新回磁盘的操作并不是在每次页发送更新时触发,而是通过一种称为 Checkpoint 的机制刷新回磁盘。这是为了提高数据库的整体性能。

LRU List、Free List 和 Flush List

缓冲区是一个很大的内存区域,其中存放各种类型的页,那么InnoDB 存储引擎怎么进行管理呢?

通常数据库中的缓冲池通过 LRU(最近最少使用)算法来进行管理的。最频繁使用的页在 LRU 列表的前端,而最少使用的页在 LRU 列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放 LRU 列表中尾端的页。

缓冲池中的页大小默认为 16KB。但是 InnoDB 存储引擎对传统的 LRU 算法做了一些优化。 LRU 列表中加入了 midpoint 位置。新读取到的页,虽然是最新访问的页,但并不是直接放入到 LRU 列表的首部,而是插入到 LRU 列表的 midpoint 位置。在默认配置下,该位置在 LRU 列表长度的 5/8 处。在 InnoDB 存储引擎中,把 midpoint之后的列表称为 old列表,之前的列表称为 new 列表。可以简单地理解为 new 列表中的页都是最活跃的热点数据。

为什么要这样优化?如果直接讲读取的页放入到 LRU 列表的首部会有什么问题?

如果将直接读取的页放入到 LRU 的首部,那么某些 SQL 操作可能会使缓冲池中的页被刷新出来,从而影响缓冲池的效率。常见的这类操作作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至全部的页,而这些页通常来说又仅在这次查询操作中需要,并不是活跃的热点数据。如果页被放入 LRU 列表的首部,那么非常可能将所需要的热点数据页从 LRU 列表中移除,而在下一次需要读取改页时,InnoDB 存储引擎需要再次访问磁盘。


执行命令 SHOW ENGINE INNODB STATUS;

Buffer pool size 共有 8192 个页

Free buffefreers表示free列表中页的数量

Database pages表示LRU列表中页的数量

Database pages与Free buffers之和不等于Buffer pool size,因为还可能分配给自适应哈希索引、lock信息、insert buffer等页。
因为是本地环境,没有做更新操作,所以即使设置了innodb_old_blocks_time,not young还是为0。
buffer pool hit rate,表示缓冲池命中率,一般不低于95%,如果偏低,要看看是不是有全表扫描造成LRU列表污染。

Free List

数据库刚启动的时候,LRU 列表为空,此时需要用到的时候直接将Free列表中的页删除,在LRU列表中增加相应的页,维持页数守恒。

Flush List

LRU列中数据被修改后,产生脏页。数据库通过checkpoint机制将脏页刷新会磁盘,flush list中的页即为脏页列表。脏页即存在于LRU中,也存在于Flush中。LRU list用于管理缓冲池中页的可用性,Flush list用于将页刷新回磁盘。

Checkpoint技术

缓冲池的设计目的是为了协调 CPU 速度与磁盘速度的鸿沟,因此页的操作首先都是在缓冲池中完成。倘若每次一个页发生变化,就将新野的版本刷新到磁盘,那么这个开销是非常大的。若热点数据集中的某几个页中,那么数据库的性能将变得非常差。同时,如果在从缓存池将页的新版本刷新到磁盘时发生宕机,那么数据就不能恢复了。为了避免发生数据丢失的问题,当前事务数据库系统普遍都采用 Write Ahead Log 策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失,通过重做日志来完成数据的恢复。

Checkpoint技术目的是结局以下几个问题:

  1. 缩短数据库的恢复时间
  2. 缓冲池不够用时,将脏页刷新到磁盘
  3. 重做日志不可用时,刷新脏页

当数据库发生宕机时,数据库不需要重做所以的日志,因为 Checkpoint 之前的页都已经刷新回磁盘。故数据库只需对 Checkpoint 后的重做日志进行恢复。这样就大大缩短了恢复的时间。

当前事务数据库系统对重做日志的设计都是循环使用的,当数据库发生宕机时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。

在 InnoDB 存储引擎内部,有两种 Checkpoint, 分别为:

  1. Sharp Checkpoint 发生在数据库关闭时将所有的脏页都刷新回磁盘
  2. Fuzzy Checkpoint 数据库在运行时只刷新一部分脏页,而不是刷新所有的脏页回磁盘

InnoDB 关键特性

  1. 插入缓冲(Insert Buffer)
  2. 两次写
  3. 自适应哈希索引
  4. 异步 IO
  5. 刷新邻接页

Insert Buffer: 对于非聚集索引的插入或更新操作,不是每一次直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入,若不在,则先放入到一个 Insert Buffer 对象中,然后再以一定的频率和情况进行 Insert Buffer 和辅助索引页子节点的 merge(合并)操作,这时通常能将多个插入合并到一个操作中去,这就大大提高了对于非聚集索引插入的性能。

Insert Buffer 的使用需要同时满足以下两个条件:

  1. 索引是辅助索引
  2. 索引不是唯一的

若是索引唯一索引,那么在插入时需要判断插入的记录是否是唯一,这需要读取辅助索引页,而insert buffer 的设计就是避免读取insert buffer,这会导致失去insert buffer 的设计意义。

doublewrite : Insert Buffer 带给 InnoDB 存储引擎的是性能上的提升,而doublewrite 带给 InnoDB 存储引擎的是数据页的可靠性。

自适应哈希索引:InnoDB 存储引擎会监控对表上各索引页的查询。如果观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引。

异步IO:为了提高磁盘操作性能,与 AIO 对应的是 Sync IO,即每进行一次 IO操作,需要等待此次操作结束才能继续接下来的操作。如果用户发出的是一条索引扫描的查询,那么这条 SQL 查询语句可能需要扫描多个索引页,也就是需要进行多次的 IO 操作。在每扫描一个页等待其完成后再进行下一次的扫描,这是没有必要的。用户可以在发出一个 IO 请求后立即再发出另一个 IO 请求,当全部 IO 请求发送完毕后,等待所有 IO 操作的完成,这就是 AIO。

刷新邻接页:当刷新一个脏页时,InnoDB 存储引擎会检测该页所在的区(extent)的所有页,如果是脏页,那么一起进行刷新。

参考

MySQL 技术内幕 InnoDB 存储引擎

发布了77 篇原创文章 · 获赞 191 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/u013164931/article/details/82423613