Mysql专栏 - 缓冲池的内部结构(一)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: Mysql专栏 - 缓冲池的内部结构(一)

前言


这一节我们来介绍缓冲池的内部结构。如果不清楚缓冲池是什么东西可以查看之前系列的第一篇文章。缓冲池最简单的理解为数据库磁盘文件在内存对应的映射,是一个十分重要的核心组件,缓冲池的内容和细节还是挺多的,这部分内容个人会限制篇幅让读者更好的消化。


缓冲池的介绍:Mysql专栏 - mysql、innodb存储引擎、binlog的工作流程#缓冲池


概述


  • Buffer pool的内部结构
  • 数据页和缓存页的关系
  • 数据页的描述信息是什么?
  • Mysql是如何知道哪些数据页被加载了
  • 脏页
  • 脏页的伪代码实现以及脏页的介绍
  • 重点
  • 分清楚free list和flush list
    熟悉整个buffer pool的结构图。


Buffer pool 结构



关于buffer pool的完整结构图如下,本文将会一一分解来讲述各个块的内容:


网络异常,图片无法展示
|


Buffer pool在mysql中地位


Buffer pool可以看作是一个内存结构的组件,可以理解为一大片的内存区域,在默认的情况下它是128m的空间大小。需要注意的是默认值比较小,通常情况下这个值是远远不够的。


从结构图来看缓冲池是非常核心的一个组件,因为mysql数据的操作不可能放到磁盘完成的,哪怕是固态硬盘也是不可能快过内存,缓冲池可以看作是数据操作的时候磁盘文件的数据的一对一映射,但是如果我们操作内存又会出现另一个问题,内存的操作是十分快的,但是硬盘的刷新速度更不上内存,所以就会出现内存和硬盘上的数据不一致的问题,种由于某些操作更新之后的内容更新过的数据页在mysql当中统称为脏页。

所以redo log、undo log、bin log这几个日志文件某种程度上可以认为是为了确保数据正确同步的策略而出现的。


网络异常,图片无法展示
|


数据页和缓存页


既然缓冲池是一块内存空间,那么数据是否在buffer pool中呢?我们的数据是如何放在buffer pool中的?

这里我们我们来回顾下数据库的逻辑结构,数据库分为表+字段+行的模式,一个表有很多行数据,那么数据页的内容就是多行?其实数据库抽取了一个叫做数据页的概念,多行数据会放到一个数据页内部,磁盘中有多个页,每一个页都有很多行数据合并到一起,最终我们更新数据就是找到某一个页的某一行。

数据页的默认大小:16kb,缓存页的大小也是16kb。

总结:buffer pool存放的是一个个数据页,也叫做缓存页,由于buffer pool是一个近似内存的缓冲池,所以硬盘的数据会转变为一个个缓存页缓存到这块“内存”当中。Buffer pool中一个缓存页和磁盘的一个数据页大小是对应的都是16kb。


缓存页的描述信息



虽然我们知道了缓存页的大小,缓存页里面存放的也是一行行的数据,但是缓存页自己是不知道这些信息的,这时候mysql引入了另一个数据块叫做缓存页的描述信息,在缓存页描述信息包含了下面的内容:


  1. 所属表空间
  2. 数据页编号
  3. 缓存页在缓冲池里面的所属地址


描述信息有多大呢?一个描述信息大概是缓存页的5%左右的大小,可能是800个字节左右的大小,默认128m的缓冲池。需要注意的是,为了防止数据页撑满缓冲池导致描述信息无法存放,mysql会给描述信息一些额外的内存空间保证描述信息可以记录所有的数据页(缓存页)。所以这里面128M不是完全固定的,会额外多个几M的缓存页描述信息


描述信息如何存放?


描述信息和缓存页按照类似“对称”的结构进行存储,描述信息放在缓存页的最前面,缓存页则放在缓冲池的最后面,至于这样设计的原因一方面是尽可能让描述信息不干扰数据页的分配,另一方面是为了让缓冲池有“额外”并且足够的空间来存放描述信息。


如何尽量减少buffer pool的内存碎片?

当缓存页和描述信息划分完数据块之后,肯定是会存在一小部分的空间是既不能分配描述信息,又不能放下缓存块的内容的,所以这部分内容没有办法使用。

如何减少呢?

在划分缓存页的时候让他们按照顺序的排列顺序紧密排列,尽可能减少浪费,其实就是顺序的分配内存。


如何知道哪些缓存页是空闲的?



那么mysql是如何知道缓存页是空闲的呢?在Buffer pool 会有一个叫做free list 双向链表,链表每一个节点就是数据页对应的描述数据块。也就是说一个数据页是空闲的,就会放到free链表中,并且在数据库刚刚启动free链表存放了所有描述信息块内容。另外,如果熟悉链表的结构,就会知道链表当中会有一个基础节点(其实就是链表的头指针,只不过内容丰富很多)来存储开始节点结束节点等内容。

至于这个基础节点的更新操作,熟悉链表的人此时一定十分清楚了,其实就是双向链表的插入操作和删除操作。


为了更好的理解上面一大段的内容,我们通过一个图来包含上面介绍的所有内容:


网络异常,图片无法展示
|


freelist占用多少内存空间?


Buffer pool 和 freelist里面的数据内容是一模一样的一份拷贝么?**大错特错!**因为描述信息在freelist里面是根据链表的节点规则串联的,同时因为这个节点只需要找到空闲缓存块即可(Free List中的所有节点都会指向一个从未被使用过的缓存页,说白了就是每个节点有个指向空闲缓存页的一对一指针)。


free list 根据链表的定义规则,每一个描述信息都有两个指针,一个是free_pre(前置节点),另一个是free_next(后继节点)。代表了一个双向链表的node,通过这两个指针就把所有的描述数据串联成一个free链表,基础的node节点本身占用了40个字节,存放头节点和尾节点的地址,以及free链表里面当前有多少个节点和其他的信息。


如何将磁盘的页读到buffer pool的缓存页?


如何把磁盘的页读到buffer pool?我们有了free list之后就可以办到了,可以从free链表获取一个描述数据块,接着可以通过这些描述信息找到对应的数据页读到缓冲池里面去,最后再把空闲列表的node去除即可。


网络异常,图片无法展示
|


如何移除节点?


其实只要通过双向链表的基础节点里面的头尾指针找到节点并且把前置节点或者后置节点的对应引用设置为null即可。也就是熟悉的双向链表的删除操作。


怎么知道数据是否真的进来了?


了解了数据页如何加载到缓冲池,接下来我们来看下mysql怎么知道哪一个数据页加载到缓冲池,一般的流程肯定是当请求进来的时候先检查缓冲池有没有数据,如果没有缓存页就需要先去free list找一下这个数据页的描述信息,然后再通过磁盘文件把这个数据页加载到缓冲池,然后再把free list对应的描述信息节点删除掉。


数据页缓存哈希表的结构是什么?


如果数据页被缓存了会直接查缓存,那么缓冲池怎么知道请求是要找它呢?其实Mysql还有一种结构是哈希表的结构,这个结构可以看作是一个Map,key保存的是表空间+数据页。而value则是缓存页的地址。当请求执行器调用接口的时候,就会根据哈希表找到对应的缓存页,如果没有缓存页就去freelist找到这块数据页加载进来。


脏页



什么是脏页?


当缓冲池的数据被更新,但是磁盘的数据和缓存页的内容不一致的时候,可以说这个页是一个“脏”页。


mysql怎么知道哪些页是脏页


那么mysql是使用free list列表进行确认的?这么做肯定不行,因为这个链表是存放的有哪些数据页没有被加载,并不能知道哪些缓存页是脏页。所以这时候mysql又引入了一个链表,叫做 flush list,它的结构和free list类似也是一个双向链表,同样有一个基础节点维护整个链表的的信息,但是和free list不同的是它所存储的是脏页的描述信息而不是所有的数据页描述信息。(同样也是在每一个节点存在一个指针指向对应的缓存页)


提示:如果还记得本系列的第一篇(前言地址)文章中简单的提到了io线程定期把缓存页刷新到磁盘文件中如何找到脏页的?其实就是通过这个双向链表来实现的,但是刷新的动作是随机刷新。此问题在后续的文章中会再次提到。

最后关于flush list的结构图放到了本文的结尾。


flushlist和freelist伪代码


下面通过两个图来分析一下两个链表的伪代码结构图,关于具体的解释都放到了代码的注释当中,这里就不多啰嗦了:


网络异常,图片无法展示
|


下面是引入第二个节点之后的内容:


网络异常,图片无法展示
|


思考题:



逻辑结构和物理结构


我们在SQL语句里都是用到的是表和行的概念,但是之前我 们提到的表空间、数据页,他们之间的关系是什么呢?

表和行是逻辑的存储结构

但是数据页,表空间,都是物理的存储结构。实际上表的数据都是放在一个表空间,表空间由数据文件(数据块)组成,数据文件存储的是一行行的数据,所以可以认为整个mysql磁盘文件抽象的理解为是由一个个数据块组成的。

物理结构和逻辑结构的区别就是他们的本质区别。


小结:


看完这篇文章相信大家有点晕了,mysql内部两个链表和一个哈希表甚至后续还会有更多的链表来维护信息,这些内容很容易混淆,所以最后再回顾前面提到的结构图来帮助读者进行回顾:


网络异常,图片无法展示
|


写在最后


缓冲池的内容看似复杂,但是参考结构图理解话其实套路是差不多的,本文的内容难度不会很难,不过到了后续随着缓冲池的细节难度会逐渐加大,最后对于内容编排有任何错误的地方欢迎指出。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
存储 算法 索引
【头歌·计组·自己动手画CPU】三、存储系统设计(HUST)(理论版) 【计算机硬件系统设计】
【头歌·计组·自己动手画CPU】三、存储系统设计(HUST)(理论版) 【计算机硬件系统设计】
1902 1
|
3天前
|
搜索推荐 编译器 Linux
一个可用于企业开发及通用跨平台的Makefile文件
一款适用于企业级开发的通用跨平台Makefile,支持C/C++混合编译、多目标输出(可执行文件、静态/动态库)、Release/Debug版本管理。配置简洁,仅需修改带`MF_CONFIGURE_`前缀的变量,支持脚本化配置与子Makefile管理,具备完善日志、错误提示和跨平台兼容性,附详细文档与示例,便于学习与集成。
271 116
|
18天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
12天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
662 219
|
5天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
344 34
Meta SAM3开源:让图像分割,听懂你的话
|
10天前
|
人工智能 移动开发 自然语言处理
2025最新HTML静态网页制作工具推荐:10款免费在线生成器小白也能5分钟上手
晓猛团队精选2025年10款真正免费、无需编程的在线HTML建站工具,涵盖AI生成、拖拽编辑、设计稿转代码等多种类型,均支持浏览器直接使用、快速出图与文件导出,特别适合零基础用户快速搭建个人网站、落地页或企业官网。
1547 157
|
存储 人工智能 监控
从代码生成到自主决策:打造一个Coding驱动的“自我编程”Agent
本文介绍了一种基于LLM的“自我编程”Agent系统,通过代码驱动实现复杂逻辑。该Agent以Python为执行引擎,结合Py4j实现Java与Python交互,支持多工具调用、记忆分层与上下文工程,具备感知、认知、表达、自我评估等能力模块,目标是打造可进化的“1.5线”智能助手。
897 61