mysql系列5—Innodb的缓存

ops/2024/12/26 22:03:02/

背景

建议读者站在设计者的角度,思考如何设计InnoDB缓存

以[mysql系列3—mysql索引图解]中的聚簇索引为例, 查询主键为33的记录:

[1] 加载聚簇索引根节点所在的数据页;
[2] 使用33与目录(21, 35)依次进行比较,得到子节点信息(地址、表空间、页号);
[3] 加载子节点所在的数据页;
[4] 使用33与目录(30, 32, 33)依次进行比较,得到叶子节点信息(地址、表空间、页号);
[5] 将叶子节点中保存的数据返回;

此过程涉及3次IO操作,由于索引和数据存放于磁盘中,3次IO均为磁盘IO,速度较慢;再次执行相同查询,仍然要经历相同的3次磁盘IO。
另外,mysql规定磁盘与内存交换的单位为数据页(16K),即查询一条记录需加载记录所在的整个页面;且处于同一页面中的数据存在关联性,可能导致同一个页面被多次冗余加载。因此,可考虑引入缓存

缓存的设计需要以数据库特性为前提,即需考虑如下几个问题:
[1] 缓存大小: 为保障数据库功能正常,需要限制缓存大小(不能无限扩大),可通过提供配置参数实现并提供合适的默认值。
[2] 缓存查询: 提供判断缓存是否已加载的能力,以及根据表空间和页序号从缓存中获取数据的能力。
[3] 缓存维护和淘汰策略: 缓存有大小限制,需要引入合适的淘汰机制,保证缓存的命中率。
[4] 缓存入库: 修改的数据需要在适当的时机入库。
本文将从这几个角度介绍InnoDB缓存

1.Buffer pool

mysql服务器启动时,会根据innodb_buffer_pool_size变量分配一块连续的内存空间用于缓存数据库数据,称为Buffer pool; 其中innodb_buffer_pool_size的默认值为134217728(128M):

mysql">mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| innodb_buffer_pool_size | 134217728 |
+-------------------------+-----------+

mysql进一步将Buffer pool划分为一个个数据页(16K),并为每个数据页创建一个对应的控制块:在这里插入图片描述
数据页用于缓存数据库数据; 控制块包含对数据页的管理信息,包括: 缓存页在Buffer pool的地址、表空间ID和数据页ID、lsn信息、链表节点信息(用于形成双向链表),控制块占据的空间远小于数据页。
有了Buffer pool后,可以将查询的数据页缓存缓存页中,并在控制块中记录数据的表空间ID和数据页ID等信息。

在此基础上,建立一个哈希表用于加快缓存查询, 将表空间ID和数据页ID的组合作为key, 缓存页地址作为value。再次访问相同的数据页时,可以先判断哈希表是否包含对应的(表空间ID数据页ID),即数据页是否在Buffer pool中;如果包含,则根据(表空间ID数据页ID)从Buffer pool内存中加载数据,否则从磁盘根据地址加载数据页至内存。

上述缓存过程存在一个问题,如何得到一个空闲的缓存页?mysql引入free链为其提供了一个解决方案。

free链
因控制块与缓存页一一对应,且控制块中包含了缓存页在Buffer Pool的地址信息;可将空闲缓存页对应的控制块保存在一起,形成一个链表:
在这里插入图片描述
mysql启动时,由于所有的缓存页都未被使用,free链包含所有的控制块。
当从磁盘加载数据页缓存到Buffer Pool时,从free链可快速得到一个空闲的缓存页,将数据页数据加载到缓存页后,从free链路中删除对应的控制块。
缓存-1被用于缓存数据后,free链的变化如下图所示:
在这里插入图片描述

flush链
数据页被加载到Buffer Pool后,mysql可对数据页进行读写;数据页被修改后就会与磁盘数据不一致,称为脏页。为保证内存与磁盘的一致性,需将脏页刷盘,而刷盘速度较慢;mysql选择对脏页进行标记,在后续的某个时间点批量同步到磁盘上。
标记的方式为将修改后的数据页对应的控制块添加到flush链路中。mysql启动时,没有数据页被修改,则flush链只有头节点,当修改缓存1时,变化如下:
在这里插入图片描述

2.lru链和淘汰策略

在第一章中介绍了Buffer Pool的结构以及free链和flush链,理解了如何加载和读取缓存页。由于Buffer Pool缓存大小是固定的,意味着需要不断地淘汰不常用的数据,以提高缓存的命中率,从而提高系统性能。本章需要考虑的问题是:确定适合的淘汰算法。

mysql特性
所谓合适是指需符合mysql的特性。
[1] 预加载
考虑到数据的相关性,从磁盘加载数据到缓存时,可进行预加载,即预先加载可能被读取的数据。mysql中有两种预加载:(1) 顺序访问某个区的页面超过阈值,触发读取下一个区的全部页面; (2) 如果某个区中连续多个页面被加载,页面数量超过阈值时,触发加载当前区的所有页面。

[2] 批量查询
mysql中可能存在大批量查询甚至全表查询情况,这些大批量的数据往往是低频使用的,易导致缓存大批量换血;且mysql的数据交换以页为单位,全表查询时,多条记录往往在同一个数据页中,会导致mysql误判数据页被频繁访问。
基于上述原因,mysql引入LRU链给出了一个解决方案。

LRU链
LRU链由两个部分组成,young区域和old区域,两个区域的节点具备流动性(类似Java的垃圾回收器)。
在这里插入图片描述
LRU链规则:
[1] 数据页第一次被加载到内存时,将控制块添加到Old区域头部;
[2] Old区域的页间隔innodb_old_blocks_time时间后再次被访问,则被认定为热点数据,移动到Yong区域头部;
[3] 位于Yong区域内的数据被访问时,移动到头节点; Yong前1/4的数据则不必移动,以减少修改频率。
LRU链涉及两个变量,可根据具体业务场景进行调优:
[1] innodb_old_blocks_pct控制OLD区域节点占据LRU整体的百分比,默认值为37:

mysql">mysql> SHOW VARIABLES LIKE 'innodb_old_blocks_pct';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+

[2] innodb_old_blocks_time控制热点数据判定的时间间隔,单位毫秒:

mysql">mysql> SHOW VARIABLES LIKE 'innodb_old_blocks_time';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_old_blocks_time | 1000  |
+------------------------+-------+

2.3 刷新脏页

将脏页刷新到磁盘的核心是选择脏页;mysql可以从flush中选择一部分数据刷入磁盘,也可以从lru的尾部选择一些脏页刷入磁盘。
**注意:**用户因查询数据而加载数据页进Buffer Pool时,如果没有足够的空间缓存,会同步处理数据释放问题,导致用户查询出现卡顿。通过调节Buffer pool大小,old区比例等参数,能一定程度减少卡顿问题出现的概率。


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

相关文章

Linux复习3——管理文件系统2

修改文件权限命令 chmod 功能: chmod 命令主要用于修改文件或者目录的权限 只有文件所有者和超级用户可以修改文件或目录的权限 (1)使用数字表示法修改权限 所谓数字表示法是指将读取(r)、写入(w)和执行(x)分别以4、2、1来表示,没有授予的部分就表示…

Charles安装证书过程(手机)

背景:使用模拟器抓包时,发现https请求无法抓取,需要安装相应证书。我自己是因为模拟器升级了安卓7,发现之前安装的证书无效了,需要重新安装。 参考博客:夜神模拟器12Charles进行Https抓包_模拟器抓包ssl-C…

从CreateDialogIndirectParam起---我与大模型对话

前言: 对当前的大模型来说,一切皆程序,皆标准。只能按照推定的线路行走,就像机器人走进死胡同,不停的踏步也不回头。除非人为去干预它。其实我提出的这个问题前是因为我不清楚了解一部分WinAPI有着严格的检查机制和自毁…

实战OpenCV之物体跟踪

基础入门 物体跟踪技术是一种计算机视觉领域的重要技术,用于连续地检测和定位视频序列中的一个或多个目标物体。物体跟踪技术在众多领域都有广泛的应用,比如:自动驾驶、安防监控、增强现实等。物体跟踪的基本流程包含以下几个主要步骤。 1、初始化:确定跟踪的目标物体及其初…

vue3导入excel并解析excel数据渲染到表格中,纯前端实现。

需求 用户将已有的excel上传到系统,并将excel数据同步到页面的表格中进行二次编辑,由于excel数据不是最终数据,只是批量的一个初始模板,后端不需要存储,所以该功能由前端独立完成。 吐槽 系统中文件上传下载预览三部…

在HTML中使用Vue如何使用嵌套循环把集合中的对象集合中的对象元素取出来(我的意思是集合中还有一个集合那种)

在 Vue.js 中处理嵌套集合(即集合中的对象包含另一个集合)时,使用多重 v-for 指令来遍历这些层次结构。每个 v-for 指令可以用于迭代一个特定级别的数据集,并且可以在模板中嵌套多个 v-for 来访问更深层次的数据。 例如&#xff…

使用 gmplot 在 Python 中创建动态地图可视化

使用 gmplot 在 Python 中创建动态地图可视化 什么是 gmplot? gmplot 是一个 Python 库,用于基于 Google Maps 的静态地图生成可视化。它提供简单的 API 来绘制标记、路径、热力图等地理信息数据。 通过 gmplot,用户可以轻松地在 Google M…

Day13 苍穹外卖项目 工作台功能实现、Apache POI、导出数据到Excel表格

目录 1.工作台 1.1 需求分析和设计 1.1.1 产品原型 1.1.2 接口设计 1.2 代码导入 1.2.1 Controller层 1.2.2 Service层接口 1.2.3 Service层实现类 1.2.4 Mapper层 1.3 功能测试 1.4 代码提交 2.Apache POI 2.1 介绍 2.2 入门案例 2.2.1 将数据写入Excel文件 2.2.2 读取Excel文…