mysql系列5—Innodb的缓存

背景

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

[mysql系列3---mysql索引图解](https://blog.csdn.net/Sheng_Q/article/details/144005610)中的聚簇索引为例, 查询主键为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区比例等参数,能一定程度减少卡顿问题出现的概率。

相关推荐
minji...2 小时前
MySQL数据库 (四) MySQL的数据类型,tinyint,float,decimal,枚举enum和集合set
数据库·mysql·tinyint·enum·decimal·varchar·bit
阿演3 小时前
DataDjinn 新版本更新:国产数据库支持、连接树体验、AI 查询和表格编辑继续增强
数据库·人工智能·ai·ai编程
一只fish3 小时前
Oracle官方文档翻译《Database Concepts 26ai》附录-术语表
数据库·oracle
一只fish3 小时前
Oracle官方文档翻译《Database Concepts 26ai》第23章-数据库开发者概念
数据库·oracle
todoitbo4 小时前
从 MySQL 到 KingbaseES:Database、Schema、User 一次讲透
数据库·mysql·国产数据库·kingbasees
Java 码思客4 小时前
【Redis分布式缓存实战】第20章 Redis监控运维与自动化体系
运维·redis·缓存
勇往直前plus4 小时前
Redis&Python 梳理
数据库·redis·python
千云4 小时前
100w大表0停机回滚:我们为什么放弃Undo Log,选择表名切换?
数据库·后端·mysql
SXJR4 小时前
使用docker 部署向量数据库Milvus
数据库·docker·容器·milvus·向量数据库
myenjoy_14 小时前
采集网关的离线缓存与断点续传——当网络不可靠时,数据一条都不能丢
网络·缓存