一、什么是 Buffer Pool
The buffer pool is an area in main memory where InnoDB
caches table and index data as it is accessed. The buffer pool permits frequently used data to be accessed directly from memory, which speeds up processing. On dedicated servers, up to 80% of physical memory is often assigned to the buffer pool
解释:
是内存中的一块区域,InnoDB 用来缓存它访问过的数据和索引。Buffer Pool 允许经常使用的数据直接从内存访问,加快了处理速度。在专门的服务器中,约 80% 的内存被用作缓冲池
For efficiency of high-volume read operations, the buffer pool is divided into pages that can potentially hold multiple rows. For efficiency of cache management, the buffer pool is implemented as a linked list of pages; data that is rarely used is aged out of the cache using a variation of the least recently used (LRU) algorithm
解释:
为了大量读取操作的效率,缓冲池被划分为可能容纳多行的页。为了缓存管理的效率,缓冲池被实现为页面的链接列表;数据很少使用的将从缓存中移除(使用变种的 LRU 算法)
Knowing how to take advantage of the buffer pool to keep frequently accessed data in memory is an important aspect of MySQL tuning
解释:
如何发挥缓冲池的有利条件是保持经常访问的数据在内存中
二、变种的 LRU 算法(重点)
当一个页将要加入到缓冲池中,最近最少使用的页将被驱逐,新的页将加入到列表的 midpoint 位置。midpoint 插入策略把列表分为 2 个部分
-
At the head, a sublist of new (“young”) pages that were accessed recently
New pages:经常访问的页
-
At the tail, a sublist of old pages that were accessed less recently
old pages:很少访问的页
如下图所示:
该算法保持经常访问的页在 new sublist
中;old sublist
包含很少访问的页,这些页将考虑被驱逐
默认情况下,算法像如下方式运行:
-
the buffer pool 的 3/8 处被对待为 old sublist
-
列表的 midpoint 位置是分界线
-
当 InnoDB 读取一个页到缓冲池中时,页的插入位置是 old sublist 的 head 部分
-
访问 old sublist 中的页会使它变『
young
』,随后把它移动到 new sublist 的 head 部分 -
随着数据库的运行,缓冲池中未被访问的页通过向列表的尾部移动而"老化",无论是 new sublist 还是 old sublist 都随着其它页变新而"老化",最终页面保留未被访问直到 old sublist 的尾部随后被驱逐
三、Buffer Pool 的优化
默认的,查询读取到的页是立刻被加入到 new sublist 的头部,意味着它们在缓冲池中长时间停留。但是有以下情况不一样
-
表扫描、不带 where 条件的 select 语句加载的页
特点:大量的页被加载到缓冲池中,尽管它们不会再被使用
-
来自后台线程的"预读"加载的页
特点:不会再被使用
使 Buffer Pool 不受表扫描影响
对比严格的 LRU 算法,InnoDB 使用一种技术来最大限度地减少进入[缓冲池]的数据量,再也没有访问过的。目标是使经常访问的页面保留在缓冲池中,即使是"提前读取"或者"全表扫描"引入可能访问或不可能访问的新块
新读取的块被插入到列表的 middle 位置,通常是距离LRU列表尾部 3/8 处。第一次在缓冲池中访问页面时,页面会移动到列表的前面(最近使用的末尾)。因此,从未被访问过的页面永远不会出现在LRU列表的前部,并且比使用严格的LRU方法更快地“老化”
-
作用:指定合适的百分比,InnoDB Buffer Pool 被用作 old block sublist 的百分比,默认值是 37
-
作用:
1、非 0 值保护反对填充 Buffer Pool,用短暂时期的停留的数据,例如在表扫描期间
2、增加这个值提供更多的保护反对表扫描的数据填充到 Buffer Pool 中
3、默认值是 1000,即 1 秒
**白话文:**就是针对表扫描加入到 old sublist 头部的页需要在 old sublist 中停留一段时间,停留一段时间后被重新访问才会加入到 new sublist 中,否则就在 old sublist 中等待驱逐
默认的,通过以上 2 个参数,可以解决预读或全表扫描带来的临时 pages 被缓存在缓冲池中的问题
配置缓冲池的预读
innodb_read_ahead_threshold
参数用来控制 InnoDB 连续页访问的敏感度。如果一个 extent 中连续读取的页大于等于该值的配置,则会开启异步 read-ahead 下一个完整的 extent 的读取。也就是说该值如果配置的越小就越敏感就越容易导致 『预读
』下一个 extent
四、Buffer Pool Configuration
你可以配置缓冲池的各个方面来提高性能
-
配置缓冲池的『
大小
』-
innodb_buffer_pool_size
> > > 缓冲池的总大小 -
innodb_buffer_pool_chunk_size
> > > 缓冲池的 chunk 大小 -
innodb_buffer_pool_instances
, > > > 缓冲池实例的个数
备注:上面 3 个配置如果随意配置会有矛盾,于是有了自适应规则,按如下规则进行:
1、如果
innodb_buffer_pool_chunk_size
*innodb_buffer_pool_instances
>innodb_buffer_pool_size
,则innodb_buffer_pool_chunk_size
=innodb_buffer_pool_size
/innodb_buffer_pool_instances
2、Buffer pool size 总是相等或者是
innodb_buffer_pool_chunk_size
*innodb_buffer_pool_instances
的倍数。如果不是倍数则需要进行自适应,自适应要求:结果大于原innodb_buffer_pool_size
配置大小,且是倍数详细的参考:Section 15.8.3.1, “Configuring InnoDB Buffer Pool Size”
-
-
配置缓冲池的『
多实例
』参考:Section 15.8.3.2, “Configuring Multiple Buffer Pool Instances”
-
使缓冲池『
不接受表扫描的页
』-
innodb_old_blocks_pct
> > > 控制缓冲池的 LRU 列表的 new sublist 和 old sublist 的比例,默认是 37,即 old sublist 占比 37% -
innodb_old_blocks_time
> > > 作用:控制新加入到 old sublist 头部的页需要在指定的时间窗口外需要被再次访问才会加入到 new sublist 中,才能更好的体现缓存经常使用的页
详细的参考:Section 15.8.3.3, “Making the Buffer Pool Scan Resistant”,这个其实在本文的上面已经提到了
-
-
配置缓冲池的『
预读
』-
该参数用来控制预读的敏感度,默认值是 56。page 在加入到 old sublist 后,必须等待 N 毫秒后,才具备 move to new sublist 的资格
详细的参考:Section 15.8.3.4, “Configuring InnoDB Buffer Pool Prefetching (Read-Ahead)”
-
-
配置缓冲池的『
刷新
』-
innodb_max_dirty_pages_pct_lwm
> > > 定义了脏页一个最低水平的预刷新百分比,目的是控制脏页的百分比阻止脏页的数量到达innodb_max_dirty_pages_pct
的大小;默认值是 10% > > > > 其实就是说脏页到达 10% 才开始刷新 -
innodb_max_dirty_pages_pct
> > > InnoDB 尝试从缓冲池中刷新脏页使脏页的百分比不超过这个值
-
-
保存存储缓冲池的状态
作用:用来减少重启服务器的预热时间
- innodb_buffer_pool_dump_at_shutdown
- innodb_buffer_pool_load_at_startup
五、监控缓冲池
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]
以下表格提供了部分指标的说明:
Name | Description |
---|---|
Total memory allocated | The total memory allocated for the buffer pool in bytes. |
Dictionary memory allocated | The total memory allocated for the InnoDB data dictionary in bytes. |
Buffer pool size | The total size in pages allocated to the buffer pool. |
Free buffers | The total size in pages of the buffer pool free list. |
Database pages | The total size in pages of the buffer pool LRU list. |
Old database pages | The total size in pages of the buffer pool old LRU sublist. |
Modified db pages | The current number of pages modified in the buffer pool. |
Pages made young | The total number of pages made young in the buffer pool LRU list (moved to the head of sublist of “new” pages). |
Pages made not young | The total number of pages not made young in the buffer pool LRU list (pages that have remained in the “old” sublist without being made young). |
Pages read | The total number of pages read from the buffer pool. |
Pages created | The total number of pages created within the buffer pool. |
Pages written | The total number of pages written from the buffer pool. |
Buffer pool hit rate | The buffer pool page hit rate for pages read from the buffer pool vs from disk storage. |
Pages evicted without access | The per second average of the pages evicted without being accessed from the buffer pool. |
LRU len | The total size in pages of the buffer pool LRU list. |
unzip_LRU len | The length (in pages) of the buffer pool unzip_LRU list. |
传送门: 保姆式Spring5源码解析
欢迎与作者一起交流技术和工作生活