【MySQL】InnoDB中的Buffer Pool

ops/2025/3/4 5:24:04/

目录

  • 1、背景
  • 2、Buffer Pool
    • 【1】含义
    • 【2】组成
    • 【3】free链表
    • 【4】哈希查找缓存页
    • 【5】flush链表
    • 【6】LRU链表
    • 【7】刷新脏页到磁盘
    • 【8】Buffer Pool实例
    • 【9】chunk
    • 【10】Buffer Pool状态信息
  • 3、总结

1、背景

mysql数据是存储在磁盘上的,但是从磁盘上读取数据的速度太慢,所以就需要把数据从磁盘读取在内存中,申请的这块内存就叫Buffer Pool,也就是缓存池的意思,接下来我们就来讲一下Buffer Pool

2、Buffer Pool

【1】含义

mysql服务启动时会申请一块存储页的连续内存,这快内存就叫Buffer Pool,Buffer Pool的大小可以通过配置文件指定,linux上的配置文件为my.cnf,windows上的配置文件为my.ini,windows上的默认配置如下,可以根据内存大小进行修改,最小值为5M:

cat my.ini | grep 'innodb_buffer_pool_size'
innodb_buffer_pool_size=128M

【2】组成

Buffer Pool是由控制块和缓存页组成,一个控制块对应一个缓存页,控制块包含对应缓存页的表空间编号、页号、缓存页在Buffer Pool中的地址、链表节点信息、锁、LSN信息, innodb_buffer_pool_size的大小并不包含控制块的空间,所以再给Buffer Pool申请一块连续的内存时会额外申请5%的空间用于存储控制块,其组成图如下:

在这里插入图片描述
如果申请的连续内存剩余空间不足以方法一个控制块和对应的缓存页,这个剩余的空间就叫碎片,如果刚好能放下控制块和对应的缓存,碎片就不存在。

【3】free链表

从磁盘读数据写到Buffer Pool中时,需要从Buffer Pool中找到空闲的缓存页去写入,为了方便快速找到哪些缓存页是空闲的,就有了free链表,也就是所有空闲缓存页对应的控制块组成的链表,其组成图如下:

在这里插入图片描述
free链表由链表基节点和控制块组成,链表基节点是额外的空间,不属于Buffer Pool,链表基节点存储了空闲缓存页对应的控制块的首地址和尾地址,还有空闲缓存页的个数,所有空闲缓存页对应的控制块组成一个双向链表。
通过free链表就可以很方便从中取出一个空闲缓存页,将其对应的控制块填入对应信息,然后从free链表中移除,再写数据到缓存页。

【4】哈希查找缓存页

查找数据时需要判断数据所在的页是否在Buffer Pool上,为了方便查找,将表空间编号和页号作为key与对应的控制模块做一个哈希表,这样就能很方便判断缓存页是否在Buffer Pool。

【5】flush链表

修改了Buffer Pool中缓存页的数据,就需要更新磁盘,每次都更新磁盘就对性能有损耗,所以可以把要更新缓存页收集起来一次性更新,需要更新的缓存页就叫脏页,所有的脏页对应的控制块可以组成一个链表叫flush链表,和free链表类似,都是由基节点和控制块组成,参考上面的free链表图。

【6】LRU链表

当free链表中找不到空闲缓存页时,就需要释放不经常使用的页,所以可以把使用评率高的缓存页放在前面,频率低的缓存页放在后面组成一个LRU链表,这个链表的插入和更新方式如下:

1、如果访问的页不在Buffer Pool中,就从磁盘加载到Buffer Pool中时,把缓存页对应的控制块放到链表的头部,
2、如果访问的页在Buffer Pool中,就直接把缓存页对应的控制块移动链表的头部。

但是有两种情况,第一是InnoDB提供了预读功能,会提前读取认为可能会访问的页到Buffer Pool中,但可能最终都没被访问;另一种情况全表扫描会把所有页都加载到Buffer Pool,但很多页后面可能不会被访问。所以为了解决这两种情况把LRU链表分为两部分:热数据和冷数据,也可以叫young区域和old区域,young区域存储使用频率高的缓存页,old区域存储使用频率不是很高的缓存页,如图:

在这里插入图片描述
LRU链表中的young区域和old区域的比例系统变量innodb_old_blocks_pct的值来确定,innodb_old_blocks_pct值代表old区域的百分比比例,如下:

mysql> SHOW VARIABLES LIKE 'innodb_old_blocks_pct';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+
1 row in set, 1 warning (0.00 sec)

通过young区域和old区域我们就可以对预读和全表扫描进行优化,预读优化如下:

当磁盘上的某个页初次加载到Buffer Pool时,就会放到old区域的头部,如果该页的访问频率低就会在old后移最终被移除。

全表扫描优化如下:

全表扫描一样也是初次会将所有页放到old区域的头部,但是后续读取所有记录代表访问了页多次,就会将页放到young区域,但是全表扫描的数据读取是一次性的,间隔很短,所以需要设置一个时间间隔,此间隔内的访问不会将页移动young区域。

时间间隔配置为innodb_old_blocks_time,单位为毫秒,配置如下:

mysql> SHOW VARIABLES LIKE 'innodb_old_blocks_time';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_old_blocks_time | 1000  |
+------------------------+-------+
1 row in set, 1 warning (0.00 sec)

【7】刷新脏页到磁盘

后台会有专门的线程会将Buffer Pool上修改过页,也就是脏页刷新到磁盘,刷新方式有两种:
第一种是BUF_FLUSH_LRU

就是定时从LRU链表尾部扫描一些页,发现脏页就更新到磁盘,扫描页的数量可以通过innodb_lru_scan_depth来指定。

查看配置如下:

mysql> SHOW VARIABLES LIKE 'innodb_lru_scan_depth';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_lru_scan_depth | 1024  |
+-----------------------+-------+
1 row in set, 1 warning (0.00 sec)

第二种刷新方式叫BUF_FLUSH_LIST

也就是定时从flush链表中刷新一部分页到磁盘。

【8】Buffer Pool实例

可以通过innodb_buffer_pool_instances配置Buffer Pool的实例,提高并发处理速度,配置如下:

mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_instances';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| innodb_buffer_pool_instances | 1     |
+------------------------------+-------+
1 row in set, 1 warning (0.00 sec)

每个Buffer Pool实例的大小为:

innodb_buffer_pool_size/innodb_buffer_pool_instances。

【9】chunk

一个Buffer Pool实例可以由多个chunk组成,一个chunk的大小可以如下查看,单位是字节:

mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_chunk_size';
+-------------------------------+-----------+
| Variable_name                 | Value     |
+-------------------------------+-----------+
| innodb_buffer_pool_chunk_size | 134217728 |
+-------------------------------+-----------+
1 row in set, 1 warning (0.00 sec)

需要注意的是innodb_buffer_pool_size的大小得是innodb_buffer_pool_instances*innodb_buffer_pool_chunk_size的整数倍。

【10】Buffer Pool状态信息

可以通过show engine innodb statu语句来查看InnoDB运行过程中的一些状态信息,其中就有Buffer Pool的状态,如下:

mysql> show engine innodb status;
...
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 1107296256
Dictionary memory allocated 6746952
Buffer pool size   64832
Free buffers       55706
Database pages     9126
Old database pages 3348
Modified db pages  8971
Percent of dirty pages(LRU & free pages): 13.837
Max dirty pages percent: 90.000
Pending reads 0
Pending writes: LRU 0, flush list 0
Pages made young 14, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 165, created 8961, written 0
0.00 reads/s, 0.00 creates/s, 0.00 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: 9126, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
...

各个字段含义如下:

Buffer Pool状态字段含义
Total memory allocated给Buffer Pool向操作系统申请的连续内存空间大小,由控制块、碎片、缓存页组成
Dictionary memory allocated给数据字典信息分配的内存空间大小,和Buffer Pool没什么关系
Buffer pool sizeBuffer Pool可以存储缓存页的数量
Free buffers空闲缓存页数量,也就是free链表节点数量
Database pagesLRU链中节点数量,包含young区域和old区域的节点
Old database pagesold区域节点的数量
Modified db pages脏页数量,也就是flush链表节点数量
Pending reads正在等待从磁盘上加载到Buffer Pool中的页面数量
Pending writes: LRU从LRU链表刷新到磁盘中的页数
Pending writes: flush list从flush链表刷新到磁盘中的页数
Page made youngLRU链表中从old区域移动到young区域头部的节点数量
Page made not young访问old区域在innodb_old_blocks_time时间间隔内访问不能移动到young区域的数量
young/s每秒从old区域移动到young区域头部节点数量
non-young/s每秒由于不满足时间限制不能从old区域移动到young区域节点数量
Page read从磁盘读取写的Buffer Pool中的页数
Page createdBuffer Pool中创建的页数
Page written刷新脏页到磁盘的页数
reads/s、creates/s、writes/s相关速度
Buffer pool hit rate某段时间平均访问1000次页面,有多少次页面已经被缓存到了Buffer Pool中
young-making rate某段时间平均访问1000次页面,有多少次访问使页面移动到了young区域,包含old、young区域移动到young区域
not某段时间平均访问1000次页面,有多少次访问没有使页面移动到了young区域
LRU sumLRU链表中节点数量
I/O sum最近50s读取磁盘页的总数
I/O cur正在读取的磁盘页数量

3、总结

Buffer Pool用作缓存,主要用于数据写入、数据读取、数据刷新,目的是为了减少磁盘I/O,增加读写速率,提高数据的访问速度和系统性能。


http://www.ppmy.cn/ops/162668.html

相关文章

1分钟用DeepSeek编写一个PDF转Word软件

一、引言 如今,在线工具的普及让PDF转Word成为了一个常见需求,常见的pdf转word工具有收费的wps,免费的有pdfgear,见下文: PDFgear:一款免费的PDF编辑、格式转化软件-CSDN博客 还有网上在线的免费pdf转word工具smallp…

一文速通 std::initializer_list

目录 用途原理加深理解 {} 和 initializer_list为什么不可以?该怎么做 用途 初始化未显示指定长度的数组,存在语法糖: int arr[] { 1, 2, 3 };C11开始,引入了**“统一初始化”**的概念STL 容器拥有类似的初始化能力,…

C语言入门资料分享源码+PDF速查手册

01 目标:掌握基础语法,能编写简单的程序 源码PDF获取 通过网盘分享的文件:C语言入门到精通.rar 链接: https://pan.baidu.com/s/1lcKj3aywRJUecLmoDeQfFg?pwdxiyx 提取码: xiyx 02 环境搭建 安装编译器(推荐GCC/MinGW/M…

【Linux第二弹】Linux基础指令(中)

目录 1.cat补充 2.echo指令(含使用) 3.more指令 (用于查看特大文件内容) 4.less指令 (用于查看特大文件内容) 5.head指令 5.1head使用实例 6.tail指令 6.1tail使用实例 7.管道指令( | ) (含使用) 8.date指令 8.1 date使用实例 9.cal指令 9.1 cal使用实例 10.完…

腾讯云扩容记录

腾讯云扩容: sudo yum install -y cloud-utils-growpart 安装扩容工具 sudo file -s /dev/vda1 有数据 sudo LC_ALLen_US.UTF-8 growpart /dev/vda 1 sudo resize2fs /dev/vda1 df -Th 完毕 以下是对执行的命令的详细解释以及背后的原理: 1. 安装 cloud…

【音视频】 H264 H265

概述 项目中接触到一些音视频领域的技术,主要对自己接触到的技术,结合自己的学习内容,进行阶段性总结,如有不正确的地方恳请指正 安防领域摄像头的编码格式目前主流的是H265,但是也存在H264的视频流。项目中经常需要…

Python入门 — 数据存储

可以使用模块 json 来存储数据。一般在程序中,程序都会把用户提供的信息存储在列表和字典等数据结构中,但是当程序关闭时,我们需要保存用户的数据,这时就需要用到模块 json ,可以比较方便的存储数据。 模块 json 让你能…

electron多进程通信

进程间通信 | Electron 进程间通信 (IPC) 是在 Electron 中构建功能丰富的桌面应用程序的关键部分之一。 由于主进程和渲染器进程在 Electron 的进程模型具有不同的职责,因此 IPC 是执行许多常见任务的唯一方法,例如从 UI 调用原生 API 或从原生菜单触发…