【MySQL 数据宝典】【内存结构】- 001 BufferPool

一、 BufferPool

BufferPool 官方文档地址

1.1 什么是 Buffer Pool

Buffer Pool 概述: Buffer Pool 是 InnoDB 存储引擎用于缓存磁盘中页的内存区域,它的大小直接影响数据库的性能。

默认大小和调整:

  • 默认情况下,Buffer Pool 的大小为 128MB,但可以根据服务器配置和需求进行调整。
  • 通过设置 MySQL 服务器配置文件中的 innodb_buffer_pool_size 参数来指定 Buffer Pool 的大小。

配置示例:

  • 举例:如果服务器有 512GB 内存,可以将数百GB分配给 Buffer Pool,以提高数据库读取性能。
  • 可在配置文件中设置 innodb_buffer_pool_size 参数,单位为字节。例如:
[server]
innodb_buffer_pool_size = 268435456

SHOW VARIABLES LIKE 'innodb_buffer_pool_size%';

[server]
innodb_buffer_pool_size = 51539607552
单位是字节
KB:51539607552 / 1024 = 50331648 KB
MB:51539607552 / (1024 * 1024) = 49152 MB
GB:51539607552 / (1024 * 1024 * 1024) = 48 GB
可以看到我们生产上使用了 48G 的 BufferPool ,当前机器规格是 32C64G

最小值限制:

  • Buffer Pool 的最小值为 5MB,如果设置的值小于 5MB,则会自动调整为 5MB。

注意事项:

  • 在配置 Buffer Pool 大小时,需要根据服务器内存资源和数据库性能需求进行权衡,以达到最佳性能和资源利用效率。

1.2 内部组成

imgimg

Buffer Pool :

  • 作用: 缓冲池,简称BP。其作用是用来缓存表数据与索引数据,减少磁盘IO操作,提升效率

  • 内存结构: 控制块+碎片+缓存页

    • 控制块被存放到 Buffer Pool 的前边,用于管理每个缓存页的控制信息。

    • 缓存页被存放到 Buffer Pool 的后边,用于存储实际的数据页内容。

  • 缓存页大小: 默认情况下,Buffer Pool 中的缓存页大小和磁盘上默认的页大小都是 16KB。

  • 控制块:

    • 存储内容: 存储着对应缓存页的所属的 表空间编号+页号+缓存页在 Buffer Pool 中的地址+链表节点信息+锁信息 等待

    • 内存大小: 每个缓存页对应的控制信息占用的内存大小是相同的,因此我们将每个页对应的控制信息称为一个控制块。控制块和缓存页是一一对应的关系。

  • 碎片: 每一个控制块都对应一个缓存页,那在分配 足够多的控制块和缓存页后,可能剩余的那点儿空间不够一对控制块和缓存页的大小,用不到了。当然,如果你把 Buffer Pool 的大小设置的刚刚好的话,也可能不会产生 碎片

注:Buffer Pool大小为128M指的就是缓存页的大小,控制块则一般占5%,所以每次会多申请6M的内存空间用于存放控制块

1.3 缓存页的哈希处理

在 InnoDB 存储引擎中,Buffer Pool 是用于缓存磁盘中页的内存区域,它的管理对数据库的性能至关重要。

Buffer Pool 管理问题

  • Buffer Pool 中的缓存页是用于存储磁盘中页的数据,但如何快速确定某个页是否已经在 Buffer Pool 中呢?
  • 传统的方法是遍历 Buffer Pool 中的所有缓存页,这样效率较低,尤其是在大型数据库系统中。

哈希表的应用

  • 哈希表结构: 我们可以利用哈希表来解决这个问题。将表空间号和页号作为键,缓存页作为值,创建一个哈希表。

  • 快速查找: 当需要访问某个页的数据时,我们可以通过哈希表快速查找对应的缓存页,而无需遍历整个 Buffer Pool。

  • 存在缓存页: 如果哈希表中存在对应的缓存页,则直接使用该缓存页中的数据,无需加载磁盘数据。

  • 不存在缓存页: 如果哈希表中不存在对应的缓存页,说明该页尚未加载到 Buffer Pool 中。此时,可以从 free 链表中选择一个空闲的缓存页,然后将磁盘中对应的页加载到该缓存页的位置。

  • Key: 表空间号+数据页号

  • Value: 对应的控制块

需要访问某个页的数据时,先从哈希表查询,如果不存在,就从 free 链表中选出一个空闲的缓冲页,把磁盘的页加载到缓冲页的位置

在 MySQL 中,确定一条数据的表空间号(tablespace ID)和页号(page number)通常是由 InnoDB 存储引擎来处理的。InnoDB 存储引擎使用了一种称为聚簇索引(clustered index)的结构来组织表中的数据,其中每个表都有一个主键索引(或称聚簇索引),主键索引的叶子节点就是数据页。

下面是确定一条数据的表空间号和页号的一般过程:

  1. 索引访问: 如果查询使用了主键或者唯一索引,那么 InnoDB 存储引擎可以直接定位到相应的数据页,跳过后续步骤。
  2. 二级索引访问: 如果查询使用了非主键索引,则首先通过非主键索引找到对应的主键值。
  3. 根据主键值查找数据: 使用主键值在主键索引上进行查找,定位到相应的数据页。
  4. 页号和表空间号: 一旦找到了数据页,InnoDB 可以从页头信息中提取表空间号和页号。通常,页头信息中包含了页号和表空间号,InnoDB 可以直接获取这些信息以确定数据的位置。

1.4 多个 Buffer Pool

img

Buffer Pool 实例化

Buffer Pool 是InnoDB向操作系统申请的一块连续的内存空间,用于缓存数据库页。在多线程环境下,访问Buffer Pool中的各种链表需要加锁处理。当Buffer Pool特别大且多线程并发访问量很高时,单一的Buffer Pool可能会影响请求处理速度。因此,我们可以将Buffer Pool拆分成若干个小的Buffer Pool实例,每个实例独立申请内存空间、管理链表等,以提高并发处理能力。

配置实例数

在服务器启动时,可以通过设置innodb_buffer_pool_instances参数来指定Buffer Pool实例的个数。例如:

[server]
innodb_buffer_pool_instances = 8

我们生产上就使用了 8个 Buffer Pool 实例,其中每个实例都是独立的,互不影响。每个Buffer Pool实例占用的内存空间可以通过以下公式计算:
innodb_buffer_pool_size / innodb_buffer_pool_instances

即总共的Buffer Pool大小除以实例的个数,得到每个实例占用的大小。

注意事项

  • innodb_buffer_pool_size的值小于1GB时,设置多个实例是无效的,InnoDB会将innodb_buffer_pool_instances的值修改为1。
  • 在Buffer Pool大小等于或大于1GB时,建议设置多个Buffer Pool实例。

通过以上方式,可以根据系统负载和并发访问情况,灵活配置Buffer Pool实例,提高数据库的并发处理能力。

1.5 Buffer Pool Chunk

在MySQL 5.7.5之后,支持在服务器运行期间调整Buffer Pool大小,但是重新调整Buffer Pool大小会耗费大量时间,因为需要重新向操作系统申请内存空间并复制数据。

为了解决这个问题,MySQL引入了Buffer Pool Chunk的概念。一个Buffer Pool实例由若干个chunk组成,每个chunk代表一片连续的内存空间,包含缓存页与其对应的控制块。

img

特点

  • 动态调整:在服务器运行期间可以以chunk为单位增加或减少内存空间,无需重新申请一大片内存并复制数据。
  • 参数设置:通过启动参数innodb_buffer_pool_chunk_size指定每个chunk的大小,默认为128M。
  • 注意事项:无法在服务器运行期间修改innodb_buffer_pool_chunk_size,因为重新调整chunk大小会耗费大量时间。

为什么不能动态修改chunk大小?

修改innodb_buffer_pool_chunk_size会导致重新申请内存空间并复制数据,耗费大量时间。而且每个chunk的大小会比设置值大约5%,以确保有足够的内存空间存储缓存页与其对应的控制块。

通过Buffer Pool Chunk的机制,MySQL在运行期间可以更加灵活地调整Buffer Pool的大小,提高了性能和效率。

关于InnoDB Buffer Pool的配置规则

  • 规则概述

  • innodb_buffer_pool_size必须是innodb_buffer_pool_chunk_size × innodb_buffer_pool_instances的倍数,以确保每个Buffer Pool实例中包含的chunk数量相同。

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

示例与解释

示例1:innodb_buffer_pool_size = 8G

-- 启动MySQL服务器时的设置
mysqld --innodb-buffer-pool-size=8G --innodb-buffer-pool-instances=16

-- 查询当前配置
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- 输出:innodb_buffer_pool_size: 8589934592(8G)

-- 若设定的大小不是2G的整数倍,系统会将其调整为最接近的2G的整数倍

示例2:innodb_buffer_pool_size = 9G

-- 启动MySQL服务器时的设置
mysqld --innodb-buffer-pool-size=9G --innodb-buffer-pool-instances=16

-- 查询当前配置
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- 输出:innodb_buffer_pool_size: 10737418240(10G)

-- 若设定的大小不是2G的整数倍,系统会将其调整为最接近的2G的整数倍

示例3:innodb_buffer_pool_size = 2G,innodb_buffer_pool_chunk_size = 256M

-- 启动MySQL服务器时的设置
mysqld --innodb-buffer-pool-size=2G --innodb-buffer-pool-instances=16 --innodb-buffer-pool-chunk-size=256M

-- 查询当前配置
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- 输出:innodb_buffer_pool_size: 2147483648(2G)

SHOW VARIABLES LIKE 'innodb_buffer_pool_chunk_size';
-- 输出:innodb_buffer_pool_chunk_size: 134217728(128M)

-- 若chunk大小乘以实例数超过了设定的Buffer Pool大小,系统会自动调整chunk大小
-- 2*1024/16=128M

当你发现这些内容对你有帮助时,为了支持我的工作,不妨给一个免费的⭐Star,这将是对我最大的鼓励!感谢你的陪伴与支持!一起在技术的路上共同成长吧!点击链接:GitHub | Gitee

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值