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日志一般放在系统表空间,但是通过参数配置后,也可以用独立表空间存放,所以用虚线表示。

相关推荐
Zzz 小生2 小时前
Claude Code学习笔记(四)-助你快速搭建首个Python项目
大数据·数据库·elasticsearch
nongcunqq5 小时前
abap 操作 excel
java·数据库·excel
rain bye bye6 小时前
calibre LVS 跑不起来 就将setup 的LVS Option connect下的 connect all nets by name 打开。
服务器·数据库·lvs
冻咸鱼6 小时前
MySQL的配置
mysql·配置
mapbar_front7 小时前
面试问题—我的问题问完了,你还有什么想问我的吗?
前端·面试
倔强青铜三7 小时前
苦练Python第67天:光速读取任意行,linecache模块解锁文件处理新姿势
人工智能·python·面试
阿里云大数据AI技术7 小时前
云栖实录|MaxCompute全新升级:AI时代的原生数据仓库
大数据·数据库·云原生
我是华为OD~HR~栗栗呀8 小时前
华为od-21届考研-C++面经
java·c语言·c++·python·华为od·华为·面试
不剪发的Tony老师8 小时前
Valentina Studio:一款跨平台的数据库管理工具
数据库·sql
weixin_307779138 小时前
在 Microsoft Azure 上部署 ClickHouse 数据仓库:托管服务与自行部署的全面指南
开发语言·数据库·数据仓库·云计算·azure