17.5.1 缓冲池
缓冲池是主内存中InnoDB
用于缓存表和索引数据的区域。缓冲池允许频繁访问的数据直接从内存中访问,从而加速处理。在专用服务器上,通常将物理内存的80%分配给缓冲池。
为了提高高容量读操作的效率,缓冲池被分割成可以存储多行的页面。为了提高缓存管理的效率,缓冲池实现为页面链表;数据较少使用的数据将使用最少最近使用(LRU)算法的变体从缓存中淘汰。
了解如何利用缓冲池来保持频繁访问的数据在内存中是一个重要的MySQL调优方面。
缓冲池 LRU 算法
缓冲池被管理为一个列表,使用LRU算法的变体。当需要添加新页面到缓冲池时,将最少最近使用的页面淘汰,并在列表中间添加新页面。这 midpoint 插入策略将列表视为两个子列表:
-
在头部,一组新的(“young”) 页面,最近访问过
-
在尾部,一组老页面,访问频率较低
算法将频繁使用的页面保留在新子列表中。老子列表包含较少使用的页面;这些页面是候选项,可能会被淘汰。
默认情况下,算法操作如下:
-
缓冲池中3/8的空间被分配给老子列表。
-
列表的中点是新子列表尾部和老子列表头部的界限处。
-
当
InnoDB
将页面读入缓冲池时,它最初将其插入到中点(老子列表头部)。一个页面可以被读取,因为它是为了用户启动的操作,如SQL查询,或者是InnoDB
自动执行的预读操作的一部分。 -
访问老子列表中的页面将其标记为““young””,将其移动到新子列表头部。如果页面是因为用户启动的操作而被读取,那么第一个访问将立即发生并将页面标记为young。如果页面是由于预读操作而被读取,那么第一个访问可能不会立即发生,也可能在页面被驱逐前不再发生。
-
随着数据库的运行,缓冲池中的页面如果没有被访问将““age””,向列表尾部移动。新子列表和老子列表中的页面都将因其他页面被标记为new而变得老。老子列表中的页面也将因页面在中点插入而变得老。最终,如果一个页面保持未使用状态,将到达老子列表的尾部并被驱逐。
默认情况下,查询读取的页面将立即移动到新的子列表中,这意味着它们在缓冲池中停留更长时间。例如,对于一个没有WHERE子句的SELECT语句或mysqldump操作,可能会将大量数据加载到缓冲池中,并驱逐等量的 older 数据,即使新数据再也不会被使用。类似地,读取背景线程加载的页面,如果只访问一次,就会移动到新的列表头部。这类情况可以推动频繁使用的页面到老子列表中,使它们变得易于驱逐。有关优化这种行为的信息,请见第17.8.3.3节,“使缓冲池扫描 resistant”和第17.8.3.4节,“配置InnoDB缓冲池预取(读取前)”。
InnoDB
标准监控器输出的BUFFER POOL AND MEMORY部分包含了缓冲池LRU算法操作的多个字段。有关详细信息,请见使用InnoDB标准监控器监控缓冲池。
缓冲池配置
您可以配置缓冲池的各个方面以提高性能。
-
理想情况下,您应该将缓冲池的大小设置为可能的最大值,留出足够的内存让服务器上的其他进程运行,而不需要过多的页面。缓冲池越大,
InnoDB
越像内存数据库,第一次从磁盘读取数据,然后在后续读取时从内存中访问数据。请参阅第 17.8.3.1 节,“配置 InnoDB 缓冲池大小”。 -
在具有足够内存的 64 位系统上,您可以将缓冲池分割成多个部分,以最小化并发操作中对内存结构的竞争。请参阅第 17.8.3.2 节,“配置多个缓冲池实例”。
-
您可以将频繁访问的数据保留在内存中,即使是突然出现的活动操作会将大量不常访问的数据加载到缓冲池中。请参阅第 17.8.3.3 节,“使缓冲池扫描 resistant”。
-
您可以控制何时和如何执行读取请求,以异步地将页面加载到缓冲池中,以预期即将出现的需求。请参阅第 17.8.3.4 节,“配置 InnoDB 缓冲池 prefetching(读取 ahead)”。
-
您可以控制背景刷新的时间点和是否根据工作负载动态调整刷新速度。有关详细信息,请见第17.8.3.5节,“配置缓冲池刷新”。
-
您可以配置
InnoDB
如何保存当前缓冲池状态,以避免服务器重启后长时间的暖启动期。有关详细信息,请见第17.8.3.6节,“保存和恢复缓冲池状态”。
使用 InnoDB 标准监控器监控 缓冲池
InnoDB
标准监控器输出,可以使用SHOW ENGINE INNODB STATUS
访问,该输出提供缓冲池操作的指标。缓冲池指标位于InnoDB
标准监控器输出中的BUFFER POOL AND MEMORY
部分:
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 2198863872
Dictionary memory allocated 776332
Buffer pool size 131072
Free buffers 124908
Database pages 5720
Old database pages 2071
Modified db pages 910
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 4, not young 0
0.10 youngs/s, 0.00 non-youngs/s
Pages read 197, created 5523, written 5060
0.00 reads/s, 190.89 creates/s, 244.94 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not
0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read
ahead 0.00/s
LRU len: 5720, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
以下表格描述了InnoDB
标准监控器报告的缓冲池指标。
InnoDB
标准监控器输出中的每秒平均值基于自上次打印InnoDB
标准监控器输出以来所经过的时间。
表17.2 InnoDB 缓冲池指标
Name | Description |
---|---|
总共分配的内存 | 缓冲池在字节中所分配的总内存。 |
词典内存分配 | InnoDB 数据字典总分配的内存大小(以字节为单位)。 |
缓冲池大小 | 缓冲池中已分配的页面总数。 |
空闲缓冲区 | 缓冲池中的空闲列表总页数。 |
数据库页面 | 缓冲池LRU列表中页面总数。 |
老数据库页面 | 缓冲池old LRU子列表中的页面总数。 |
修改的数据库页面 | 当前缓冲池中已修改的页面数量。 |
等待读取 | 缓冲池中等待被读入的页面数量。 |
LRU pending writes | 缓冲池中的老脏页面,需要从LRU列表底部写回的数量。 |
flush list pending writes | checkpointing期间需要被刷新的缓冲池页面数量。 |
单页pending writes | 缓冲池中独立写入的pending页面数量。 |
Pages made young | 缓冲池LRU列表中的总young页面数量(从“new”子列表移动到头部)。 |
Pages made not young | 缓冲池LRU列表中的总不young页面数量(在“old”子列表中没有被young的页面)。 |
youngs/s | 每秒平均访问老页面的次数,结果使页面young。请参阅以下表格注释以获取更多信息。 |
non-youngs/s | 缓冲池LRU列表中每秒平均访问老页面的次数,未使页面年轻。请参阅以下表格后的注释以获取更多信息。 |
读取页数 | 缓冲池中总共读取的页数。 |
创建页数 | 缓冲池中创建的总页数。 |
写入页数 | 从缓冲池中写入的总页数。 |
每秒读取次数/s | 每秒平均缓冲池页读取次数。 |
创建/秒 | 每秒平均缓冲池页创建次数。 |
写入/秒 | 每秒平均缓冲池页写入次数。 |
缓冲池命中率 | 从缓冲池读取 vs 从磁盘存储的缓冲池页命中率。 |
使页面年轻率 | 每秒平均访问页面时使页面年轻的次数。请参阅以下表格后的注释以获取更多信息。 |
未使页面年轻率 | 每秒平均访问页面时未使页面年轻的次数。请参阅以下表格后的注释以获取更多信息。 |
预读页数 | 每秒平均预读操作次数。 |
未访问页数 | 每秒平均从缓冲池中未访问的页数。 |
随机预读 | 每秒平均随机预读操作次数。 |
LRU列表长度 | 缓冲池LRU列表总大小(页数)。 |
unzip_LRU列表长度 | 缓冲池unzip_LRU列表的长度(页数)。 |
I/O总和 | 缓冲池LRU列表页总访问次数。 |
I/O当前 | 当前时间间隔内的缓冲池LRU列表页总访问次数。 |
I/O解压缩和 | 缓冲池unzip_LRU列表页总解压缩次数。 |
I/O当前解压缩 | 当前时间间隔内的缓冲池unzip_LRU列表页总解压缩次数。 |
注意:
-
youngs/s
指标仅适用于老页面。它基于页面访问次数。对于给定的页面,可以有多个访问,所有访问都被计数。如果您在没有大扫描的情况下看到youngs/s
值非常低,考虑减少延迟时间或增加缓冲池中用于老子列表的百分比。增加百分比使老子列表更大,使得那些页面更长时间内不能移动到尾部,从而增加了这些页面被访问并且变为年轻的可能性。请参阅第17.8.3.3节,“使缓冲池扫描抵抗”。 -
non-youngs/s
指标仅适用于老页面。它基于页面访问次数。对于给定的页面,可以有多个访问,所有访问都被计数。如果您在执行大表扫描时不见non-youngs/s
值增加(并且youngs/s
值也增加),请增加延迟值。请参阅第17.8.3.3节,“使缓冲池扫描抵抗”。 -
young-making
率涵盖了所有缓冲池页面访问,而不仅限于老子列表中的页面访问。young-making
率和not
率通常不会相加到总的缓冲池命中率。老子列表中的页面命中会将页面移动到新子列表,而新子列表中的页面命中只会将页面移动到头部,如果它们距离头部有一定的距离。 -
not (young-making rate)
是平均命中率,表示由于innodb_old_blocks_time
未满足或新子列表中的页面命中没有导致页面被移动到头部的访问次数。这率涵盖了所有缓冲池页面访问,而不仅限于老子列表中的页面访问。
缓冲池服务器状态变量和INNODB_BUFFER_POOL_STATS
表提供了许多在InnoDB
标准监控输出中找到的一些缓冲池指标。更多信息,请见Example 17.10,“Querying the INNODB_BUFFER_POOL_STATS Table”。