Buffer Pool 相关参数

158 阅读8分钟

线性预读(顺序访问了某个区( extent )的页面超过这个系统变量的值,就会触发一次 异步 读取下一个区中全部的页面到 Buffer Pool 的请求),值默认是 56 SET GLOBAL innodb_read_ahead_threshold = 66

随机预读 默认值的 OFF SET GLOBAL innodb_random_read_ahead = ON

LRU链表冷热数据区的占比(默认37%)

image.png

查看: SHOW VARIABLES LIKE 'innodb_old_blocks_pct';

设置:SET GLOBAL innodb_old_blocks_pct = 40;

冷数据进入热数据时间访问间隔(默认1000ms)

image.png

查看: SHOW VARIABLES LIKE 'innodb_old_blocks_time';

设置: SET GLOBAL innodb_old_blocks_time = 2000;

Buffer Pool 实例个数(innodb_buffer_pool_size的值小于1G的时候设置多个实例是无效的,InnoDB会默认把innodb_buffer_pool_instances 的值修改为1)

SET GLOBAL innodb_buffer_pool_instances = 2;

每个 Buffer Pool 实例实际占多少内存空间呢:innodb_buffer_pool_size/innodb_buffer_pool_instances

查看Buffer Pool的状态信息

SHOW ENGINE INNODB STATUS

image.png

我们来详细看一下这里边的每个值都代表什么意思:

  • Total memory allocated :代表 Buffer Pool 向操作系统申请的连续内存空间大小,包括全部控制块、缓 存页、以及碎片的大小。
  • Dictionary memory allocated :为数据字典信息分配的内存空间大小,注意这个内存空间和 Buffer Pool 没啥关系,不包括在 Total memory allocated 中。
  • Buffer pool size :代表该 Buffer Pool 可以容纳多少缓存 页 ,注意,单位是 页 !
  • Free buffers :代表当前 Buffer Pool 还有多少空闲缓存页,也就是 free链表 中还有多少个节点。
  • Database pages :代表 LRU 链表中的页的数量,包含 young 和 old 两个区域的节点数量。
  • Old database pages :代表 LRU 链表 old 区域的节点数量。
  • Modified db pages :代表脏页数量,也就是 flush链表 中节点的数量。
  • Pending reads :正在等待从磁盘上加载到 Buffer Pool 中的页面数量。当准备从磁盘中加载某个页面时,会先为这个页面在 Buffer Pool 中分配一个缓存页以及它对应的控制块, 然后把这个控制块添加到 LRU 的 old 区域的头部,但是这个时候真正的磁盘页并没有被加载进来, Pending reads 的值会跟着加1。
  • Pending writes LRU :即将从 LRU 链表中刷新到磁盘中的页面数量。
  • Pending writes flush list :即将从 flush 链表中刷新到磁盘中的页面数量。
  • Pending writes single page :即将以单个页面的形式刷新到磁盘中的页面数量。
  • Pages made young :代表 LRU 链表中曾经从 old 区域移动到 young 区域头部的节点数量。这里需要注意,一个节点每次只有从 old 区域移动到 young 区域头部时才会将 Pages made young 的值加 1,也就是说如果该节点本来就在 young 区域,由于它符合在 young 区域1/4后边的要求,下一次访问这个页 面时也会将它移动到 young 区域头部,但这个过程并不会导致 Pages made young 的值加1。
  • Page made not young :在将 innodb_old_blocks_time 设置的值大于0时,首次访问或者后续访问某个处 在 old 区域的节点时由于不符合时间间隔的限制而不能将其移动到 young 区域头部时, Page made not young 的值会加1。这里需要注意,对于处在 young 区域的节点,如果由于它在 young 区域的1/4处而导致它没有被移动到 young 区域头部,这样的访问并不会将 Page made not young 的值加1。
  • youngs/s :代表每秒从 old 区域被移动到 young 区域头部的节点数量。
  • non-youngs/s :代表每秒由于不满足时间限制而不能从 old 区域移动到 young 区域头部的节点数量。
  • Pages read 、 created 、 written :代表读取,创建,写入了多少页。后边跟着读取、创建、写入的速 率。
  • Buffer pool hit rate :表示在过去某段时间,平均访问1000次页面,有多少次该页面已经被缓存到 Buffer Pool 了。
  • young-making rate :表示在过去某段时间,平均访问1000次页面,有多少次访问使页面移动到 young 区 域的头部了。需要注意的一点是,这里统计的将页面移动到 young 区域的头部次数不仅仅包含从 old 区域移动到 young 区域头部的次数,还包括从 young 区域移动到 young 区域头部的次数(访问某个 young 区域的节 点,只要该节点在 young 区域的1/4处往后,就会把它移动到 young 区域的头部)。
  • not (young-making rate) :表示在过去某段时间,平均访问1000次页面,有多少次访问没有使页面移动 到 young 区域的头部。需要注意的一点是,这里统计的没有将页面移动到 young 区域的头部次数不仅仅包含因为设置了innodb_old_blocks_time 系统变量而导致访问了 old 区域中的节点但没把它们移动到 young 区域的次数, 还包含因为该节点在 young 区域的前1/4处而没有被移动到 young 区域头部的次数。
  • LRU len :代表 LRU链表 中节点的数量。
  • unzip_LRU :代表 unzip_LRU链表 中节点的数量(由于我们没有具体唠叨过这个链表,现在可以忽略它的 值)。
  • I/O sum :最近50s读取磁盘页的总数。
  • I/O cur :现在正在读取的磁盘页数量。
  • I/O unzip sum :最近50s解压的页面数量。
  • I/O unzip cur :正在解压的页面数量。

MySQL 5.7.5 之前, Buffer Pool 的大小只能在服务器启动时通过配置 innodb_buffer_pool_size 启动参数 来调整大小,在服务器运行过程中是不允许调整该值的。MySQL 5.7.5 版本之后,可以在服务器运行过程中调整 Buffer Pool 大小,但是有一个问题,就是每次当我们要重新调整 Buffer Pool 大小时,都需要重新向操作系统申请一块连续的内存空间,然后将旧的 Buffer Pool 中的内容复制到这一 块新空间,这是极其耗时的。所以设计 MySQL 的大叔们决定不再一次性为某个 Buffer Pool 实例向操作系统申请 一大片连续的内存空间,而是以一个所谓的 chunk 为单位向操作系统申请空间。也就是说一个 Buffer Pool 实例 其实是由若干个 chunk 组成的,一个 chunk 就代表一片连续的内存空间,里边儿包含了若干缓存页与其对应的控 制块,画个图表示就是这样:

image.png

上图代表的 Buffer Pool 就是由2个实例组成的,每个实例中又包含2个 chunk 。 正是因为发明了这个 chunk 的概念,我们在服务器运行期间调整 Buffer Pool 的大小时就是以 chunk 为单位增 加或者删除内存空间,而不需要重新向操作系统申请一片大的内存,然后进行缓存页的复制。

这个所谓的 chunk的大小是我们在启动操作 MySQL 服务器时通过 innodb_buffer_pool_chunk_size 启动参数指定的,它的默认值是 134217728 ,也就是 128M 。不过需要注意的是,innodb_buffer_pool_chunk_size的值只能在服务器启动时指定,在服务器运行过程中是不可以修改的。

SET GLOBAL innodb_buffer_pool_chunk_size = 134217728;

配置Buffer Pool时的注意事项

  • innodb_buffer_pool_size 必须是 innodb_buffer_pool_chunk_size × innodb_buffer_pool_instances 的 倍数(这主要是想保证每一个 Buffer Pool 实例中包含的 chunk 数量相同)。

假设我们指定的 innodb_buffer_pool_chunk_size 的值是 128M , innodb_buffer_pool_instances 的值是 16 ,那么这两个值的乘积就是 2G ,也就是说 innodb_buffer_pool_size 的值必须是 2G 或者 2G 的整数 倍。比方说我们在启动 MySQL 服务器是这样指定启动参数的:

mysqld --innodb-buffer-pool-size=8G --innodb-buffer-pool-instances=16

默认的 innodb_buffer_pool_chunk_size 值是 128M ,指定的 innodb_buffer_pool_instances 的值是 16 , 所以 innodb_buffer_pool_size 的值必须是 2G 或者 2G 的整数倍,上边例子中指定的 innodb_buffer_pool_size 的值是 8G ,符合规定,所以在服务器启动完成之后我们查看一下该变量的值就 是我们指定的 8G (8589934592字节):

show variables like 'innodb_buffer_pool_size';

image.png

如果我们指定的 innodb_buffer_pool_size 大于 2G 并且不是 2G 的整数倍,那么服务器会自动的把 innodb_buffer_pool_size 的值调整为 2G 的整数倍,比方说我们在启动服务器时指定的 innodb_buffer_pool_size 的值是 9G :

mysqld --innodb-buffer-pool-size=9G --innodb-buffer-pool-instances=16

那么服务器会自动把 innodb_buffer_pool_size 的值调整为 10G (10737418240字节),不信你看:

image.png

  • 如果在服务器启动时, 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 的值。

比方说我们在启动服务器时指定的 innodb_buffer_pool_size 的值为 2G , innodb_buffer_pool_instances 的值为16, innodb_buffer_pool_chunk_size 的值为 256M :

mysqld --innodb-buffer-pool-size=2G --innodb-buffer-pool-instances=16 --innodb-buffe r-pool-chunk-size=256M

由于 256M × 16 = 4G ,而 4G > 2G ,所以 innodb_buffer_pool_chunk_size 值会被服务器改写为 innodb_buffer_pool_size/innodb_buffer_pool_instances 的值,也就是: 2G/16 = 128M (134217728字 节),不信你看:

image.png