InnoDB引擎底层解析(二)之InnoDB的Buffer Pool(三)

Buffer Pool 实例

我们上边说过,Buffer Pool 本质是 InnoDB 向操作系统申请的一块连续的内存空间,在多线程环境下,访问 Buffer Pool 中的各种链表都需要加锁处理,在Buffer Pool特别大而且多线程并发访问特别高的情况下,单一的 Buffer Pool 可能会影响请求的处理速度。所以在 Buffer Pool 特别大的时候,我们可以把它们拆分成若干个小的 Buffer Pool ,每个 Buffer Pool 都称为一个实例,它们都是独立的,独立地去申请内存空间,独立的管理各种链表,所以在多线程并发访问时并不会相互影响,从而提高并发处理能力。

我们可以在服务器启动的时候,通过设置innodb_buffer_pool_instances的值来修改Buffer Pool实例的个数,那每个Buffer Pool实例实际占多少内存空间呢?其实使用这个公式算出来的:

innodb_buffer_pool_size/innodb_buffer_pool_instances

也就是每个 Buffer Pool 实例占用的大小等于 buffer pool 缓冲池总共的大小除以实例的个数。

innodb_buffer_pool_chunk_size

在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 就代表一片连续的内存空间,里边儿包含了若干缓存页与其对应的控制块:

正是因为发明了这个 chunk 的概念,我们在服务器运行期间调整 Buffer Pool 的大小时就是以chunk为单位增加或者删除内存空间,而不需要重新向操作系统申请一片大的内存,然后进行缓存页的复制。这个所谓的 chunk 的大小是我们在启动操作MySQL服务器时通过innodb_buffer_pool_chunk_size启动参数指定的,它的默认值是134217728,也就是128M。不过需要注意的是,innodb_buffer_pool_chunk_size的值只能在服务器启动时指定,在服务器运行过程中是不可以修改的。

mysql 复制代码
show variables like 'innodb_buffer_pool_chunk_size';

Buffer Pool 的缓存页除了用来缓存磁盘上的页面以外,还可以存储锁信息、自适应哈希索引等信息。

查看Buffer Pool的状态信息

MySQL 给我们提供了 SHOW ENGINE INNODB STATUS 语句来查看关于 InnoDB 存储引擎运行过程中的一些状态信息,其中就包括 Buffer Pool 的一些信息,我们看一下(为了突出重点,我们只把输出中关于 Buffer Pool 的部分提取了出来):

mysql 复制代码
show engine innodb status\G

这里边的每个值都代表什么意思如下,知道即可:

  • Total large 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中的页面数量。
  • Pending writes
    • LRU:即将从LRU链表中刷新到磁盘中的页面数量。
    • flush list:即将从flush链表中刷新到磁盘中的页面数量。
    • single page:即将以单个页面的形式刷新到磁盘中的页面数量。
  • Pages made young:代表LRU链表中曾经从old区域移动到young区域头部的节点数量
  • Page made not young :在将innodb_old_blocks_time设置的值大于0时,首次访问或者后续访问某个处在old区域的节点时由于不符合时间间隔的限制而不能将其移动到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区域的头部了。
  • not(young-making rate):表示在过去某段时间,平均访问1000次页面,有多少次访问没有使页面移动到young区域的头部。
  • LRU len:代表LRU链表中节点的数量。
  • unzip_LRU:代表unzip_LRU链表中节点的数量。
  • I/O sum:最近50s读取磁盘页的总数。
  • I/O cur:现在正在读取的磁盘页数量。
  • I/O unzip sum:最近50s解压的页面数量。
  • I/O unzip cur:正在解压的页面数量。

InnoDB的内存结构总结

InnoDB的内存结构和磁盘存储结构图总结如下:

其中的 Insert/Change Buffer 主要是用于对二级索引的写入优化,Undo空间则是undo日志一般放在系统表空间,但是通过参数配置后,也可以用独立表空间存放,所以用虚线表示。

相关推荐
诗句藏于尽头21 分钟前
DJANGO后端服务启动报错及解决
数据库·笔记·django
手握风云-31 分钟前
MySQL数据库精研之旅第十五期:索引的 “潜规则”(下)
数据库
失散131 小时前
分布式专题——1.1 Redis单机、主从、哨兵、集群部署
java·数据库·redis·分布式·架构
刘一说1 小时前
Spring Boot+Nacos+MySQL微服务问题排查指南
spring boot·mysql·微服务
2301_779503761 小时前
MySQL集群高可用架构---mysql高可用之组复制 (MGR)
数据库·mysql·架构
叁沐1 小时前
MySQL 31 误删数据后除了跑路,还能怎么办?
mysql
UrbanJazzerati1 小时前
掌握 xlwings 的 used_range:高效处理 Excel 数据区域
python·面试·excel
Hello.Reader2 小时前
一文通关 Proto3完整语法与工程实践
java·linux·数据库·proto3
青鱼入云2 小时前
【面试场景题】spring应用启动时出现内存溢出怎么排查
spring·面试·职场和发展
007php0072 小时前
Go语言面试:传值与传引用的区别及选择指南
java·开发语言·后端·算法·面试·golang·xcode