当前位置: 首页 > news >正文

MySQL之深入InnoDB存储引擎——Buffer Pool

文章目录

    • 一、空闲链表的管理
    • 二、缓冲页的哈希处理
    • 三、Flush链表的管理
    • 四、LRU链表的管理
    • 五、脏页刷新
    • 六、多Buffer Pool实例

InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。在数据库系统中,由于CPU速度与磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能。在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,这个过程称为将页“FIX”在缓冲池中,在下一次读取相同的页时,首先判断该页是否存在缓冲池中,如果存在则被命中,直接读取,否则读取磁盘上的页。

Buffer Pool对应的一片连续的内存被划分为若干个页面,页面大小和InnoDB表空间使用的页面大小一致,默认都是16KB。为了更好地管理Buffer Pool中的这些缓冲页,InnoDB为每个缓冲页都创建了一个控制块,其中包含该页所属的表空间编号、页号、缓冲页在Buffer Pool中的地址、链表节点等信息。控制块位于Buffer Pool的内存的前部分,缓冲页位于Buffer Pool的后部分,两部分之间可能会存在碎片(如果剩余的空间不足够再分配一堆控制块和缓冲页则会产生)。

一、空闲链表的管理

在我们最开始启动MySQL服务器的时候,需要向操作系统申请Buffer Pool的内存空间,然后把它换分成若干对控制块和缓冲页。当然此时没有真实的磁盘页被缓存到Buffer Pool中,会随着程序的运行不断缓存。

当从磁盘上读取到一个页时,我们需要将其放置在空闲的缓冲页中。那我们就需要区分哪些页是空闲的,哪些页已经被使用了,因此引入了Free链表(空闲链表)。在Buffer Pool刚刚完成初始化之后,所有缓冲页对应的控制块都会加入到空闲链表中。而为了管理这个空闲链表,我们为其定义了一个基节点,其中包含了链表的头节点地址、尾节点地址以及当前链表中节点的数量等信息。需要注意的是,链表的基节点占用的内存空间并不包含在为Buffer Pool申请的一大片连续内存孔内,而是一块单独申请的内存空间。

有了空闲链表之后,每当需要从磁盘中加载一个页到Buffer Pool中时,就从空闲链表中取一个缓冲页对应的控制块,把页加载到控制块指向的缓冲页中,并把该控制块的信息给填上(即表空间、页号等)。

二、缓冲页的哈希处理

使用了Buffer Pool之后,我们访问某个页的数据时会先去缓冲池中查找该页是否已经加载到内存中,如果不存在才会去磁盘中加载。而为了快速判断目标页是否存在于缓冲池中,InnoDB采用的是哈希表的方式,将表空间号和页号作为键,缓冲页控制块作为值来进行构建。

三、Flush链表的管理

如果我们修改了Buffer Pool中某个缓冲页的数据,那其中的数据就和磁盘中的不同了,此时这个缓冲页变为了脏页。虽然我们可以在每次修改完都将其刷新到磁盘中对应的页上,但是这显然会严重影响程序的性能。因此InnoDB不会在每次修改完页都立刻刷库,而是在未来某个时间点进行刷新。

既然不是及时刷新,那我们在未来刷新时便需要知道哪些页是脏页。因此引入了Flush链表进行脏页的管理,当缓冲页被修改则将其控制块加入到链表中。

和空闲链表相同,它也有一个相同结构的基节点来保存这个链表的信息。显然当一个缓冲页的控制块在空闲链表中时则不可能在Flush链表中,反之同理。

四、LRU链表的管理

Buffer Pool对应的内存大小毕竟是有限的,随着程序的运行Free链表总归会用完。如果Free链表已经没有多余的空闲缓冲页了,那么只能将某些旧的缓冲页从Buffer Pool中淘汰,再将新的页放进来。Buffer Pool引入的初衷是为了想减少磁盘IO,因此自然希望淘汰掉的页面是最少使用的,而最近经常使用的页面不被淘汰,因此InnoDB采用的淘汰策略为LRU,即最近最少使用算法。以这个算法为核心,InnoDB维护了一个LRU链表,如果页不在Buffer Pool中,在把该页从磁盘加载到Buffer Pool的时候,就把该缓冲页对应的控制块作为节点添加到LRU链表的头部,如果使用到链表中的某个页时也将其移动到链表头部。之后当空闲缓冲页用完时,就从链表尾部进行淘汰。

但这种实现并不完善,它存在两个问题:

  1. 因为InnoDB提供了预读的功能,即InnoDB认为执行当前的请求时,可能会在后面读取某些页面,于是就预先把这些页面加载到Buffer Pool中。根据触发方式的不同,预读可分为以下两种:

    • 线性预读:InnoDB中有一个系统变量innodb_read_ahead_threshold,如果顺序访问某个区的页面超过这个系统变量的值,则会触发一次异步读取下一个区中所有页面的请求
    • 随机预读:如果某个区的13个连续的页面都被加载到了Buffer Pool中,无论这些页面是不是顺序读取的,都会触发一次异步读取本区中所有其他页面到Buffer Pool中的请求。这个功能默认不会开启
    • 预读到Buffer Pool中的页如果能够被成功的使用到,那自然可以极大地提高语句执行的效率。但是如果用不到,会导致LRU链表尾部的一些缓冲页很快就被淘汰掉,从而大大降低Buffer Pool的命中率
  2. 有的时候可能需要用到全表扫描,这个过程中需要访问的页面一般会特别多,那么就会导致LRU链表中很多页面都会被淘汰掉。但是这次全表扫描引进来的这些页面可能并不是热点数据,但是反而把热点数据从链表中赶跑了

为了避免以上两种情况把Buffer Pool中真正的热点数据淘汰,InnoDB将LRU分成两个部分:

  1. 一部分存储使用频率非常高的缓冲页,称为热数据或young数据
  2. 一部分存储使用频率不是很高的缓冲页,称为冷数据或old数据

LRU的划分是根据比例的,默认情况下old区域占LRU链表的37%。之后当磁盘的页面被初次加载到Buffer Pool中时,该缓冲页对应的控制块会放置到old区域的头部,而不再是整个链表的头部,这样就不会使得预读加载进来的页影响young区域中使用比较频繁的缓冲页。并且在对某个处于old区域的缓冲页进行第一次访问时,会在它对应的控制块中记录下整个访问时间,如果后续的访问时间与第一次访问的时间在某个时间间隔内,那么该页面就不会从old区域移动到young区域头部。这样一来也可以防止全表扫描时除了将数据页加载到Buffer Pool,还会频繁读取页面中的记录导致仍然会淘汰掉热点数据的情况。

除了以上的改进,LRU还有进一步的优化策略。对于young区域的缓冲页来说,如果我们每次访问一个缓冲页都需要把它移动到LRU链表的头部,其实开销是比较大的,因为young区域都是热点数据。因此InnoDB规定只有被访问的缓冲页位于young区域1/4的后面时,才会被移动到LRU链表的头部。

五、脏页刷新

后台有专门的线程负责每隔一段时间就把脏页刷新到磁盘,这样可以不影响用户线程处理正常的请求,刷新的方式主要有两种:

  1. 从LRU链表的冷数据中刷新一部分页面到磁盘:后台线程会定时从LRU链表尾部开始扫描一些页面。如果在LRU链表中发现脏页(缓冲页的控制块就会记录该缓冲页是否被修改),则把它们刷新到磁盘
  2. 从Flsuh链表中刷新一部分到磁盘:后台线程也会定时从Flush链表中刷新一部分页面到磁盘,刷新的速率取决于当时系统是否繁忙

当有线程在准备加载一个磁盘页到Buffer Pool中时没有可用的缓冲页时会尝试查看LRU链表尾部,看是否存在可以直接释放掉的未修改缓冲页。有时后台线程刷新脏页的进度比较慢,导致LRU链表尾部的脏页还没有被刷新,此时则不得不将LRU链表尾部的一个脏页同步刷新到磁盘中,这会降低用户请求的速度。

六、多Buffer Pool实例

在多线程环境下,访问Buffer Pool中的各个链表都需要加锁处理。在Buffer Pool特别大并且多线程并发量特别高的情况下,单一的Buffer Pool可能会影响请求的处理速度。所以在Buffer Pool特别大时,可以把它们拆分成若干个小的Buffer Pool,每个Buffer Pool都称为一个实例。它们之间是相互独立的,多线程并发时不会互相影响。

相关文章:

MySQL之深入InnoDB存储引擎——Buffer Pool

文章目录 一、空闲链表的管理二、缓冲页的哈希处理三、Flush链表的管理四、LRU链表的管理五、脏页刷新六、多Buffer Pool实例 InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。在数据库系统中,由于CPU速度与磁盘速度之间的鸿沟&…...

网络安全(秋招)如何拿到offer?(含面试题)

以下为网络安全各个方向涉及的面试题,星数越多代表问题出现的几率越大,祝各位都能找到满意的工作。 注:本套面试题,已整理成pdf文档,但内容还在持续更新中,因为无论如何都不可能覆盖所有的面试问题&#xf…...

笙默考试管理系统-MyExamTest----classranking(2)

笙默考试管理系统-MyExamTest----classranking(2) 目录 笙默考试管理系统-MyExamTest----classranking(2) 一、 笙默考试管理系统-MyExamTest----classranking 二、 笙默考试管理系统-MyExamTest----classranking 三、 笙…...

基于python的一个元素多种定位方式

基于 Python 的 Page Factory 设计模式测试库, 类似于Java的Page Factory模式,旨在减少代码冗余,简单易用,具有高度的可扩展能力。 支持以annotation的方式定义元素 支持同一个元素多种定位方式 支持动态的定位方式 安装 pip install pyth…...

Fastdfs集群搭建

一、简单介绍: FastDFS是一个开源的高性能分布式文件系统(DFS)。 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡。主要解决了海量数据存储问题,特别适合以中小文件&…...

【深度学习】Vision Transformer论文,ViT的一些见解《 一幅图像抵得上16x16个词:用于大规模图像识别的Transformer模型》

必看文章:https://blog.csdn.net/qq_37541097/article/details/118242600 论文名称: An Image Is Worth 16x16 Words: Transformers For Image Recognition At Scale 论文下载:https://arxiv.org/abs/2010.11929 官方代码:https:…...

在centos7上使用非编译方式安装ffmpeg

很多在centos7上安装ffmpeg的教程都需要使用编译方式的安装;编译时间较长而且需要配置; 后来搜索到可以通过加载rpm 源的方式实现快速便捷操作 第一种方式: 首先需要安装yum源: yum install epel-release yum install -y https://mirrors.…...

【微信小程序】导出Excel文件

// 导出 doOutExcel() {let fileName 考勤列表wx.request({url: XXX,method: POST,header: {"content-type": "application/json","Authorization": "token " wx.getStorageSync(userInfo).token},data: {}, // 请求参数responseTyp…...

接口测试—知识速查(Postman)

文章目录 接口测试1. 概念2. 原理3. 测试流程4. HTTP协议4.1 URL的介绍4.2 HTTP请求4.2.1 请求行4.2.2 请求头4.2.3 请求体4.2.4 完整的HTTP请求示例 4.3 HTTP响应4.3.1 状态行4.3.2 响应头4.3.3 响应体4.3.4 完整的HTTP请求示例 5. RESTful接口规范6. 测试用例的设计思路6.1 单…...

机器学习深度学习——序列模型(NLP启动!)

👨‍🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习&&深度学习——卷积神经网络(LeNet) 📚订阅专栏:机器学习&&深度…...

小白到运维工程师自学之路 第六十四集 (dockerfile构建tomcat、mysql、lnmp、redis镜像)

一、tomcat&#xff08;更换jdk&#xff09; mkdir tomcat cd tomcat/ tar xf jdk-8u191-linux-x64.tar.gz tar xf apache-tomcat-8.5.40.tar.gzvim Dockerfile FROM centos:7 MAINTAINER Crushlinux <syh163.com> ADD jdk1.8.0_191 /usr/local/java ENV JAVA_HOME /us…...

超低功耗水表电器表LCD驱动显示芯片,高抗干扰性能提供LQFP48、LQFP64的封装

VK2C23是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大224点&#xff08;56SEGx4COM&#xff09;或者最大416点&#xff08;52SEGx8COM&#xff09;的LCD屏。单片机可通过I2C接口配置显示参数和读写显示数据&#xff0c;也可通过指令进入省电模式。其高抗干扰&#xff…...

SpringBoot3---核心特性---2、Web开发III(模板引擎、国际化、错误处理)

星光下的赶路人star的个人主页 夏天就是吹拂着不可预期的风 文章目录 1、模板引擎1.1 Thymeleaf1.2 基础语法1.3 属性设置1.4 遍历1.5 判断1.6 属性优先级1.7 行内写法1.8 变量选择1.9 模板布局1.10 devtools 2、国家化3、错误处理3.1 默认机制3.2 自定义错误响应3.3 最佳实战 …...

MemFire教程|FastAPI+MemFire Cloud+LangChain开发ChatGPT应用-Part2

基本介绍 上篇文章我们讲解了使用FastAPIMemFire CloudLangChain进行GPT知识库开发的基本原理和关键路径的代码实现。目前完整的实现代码已经上传到了github&#xff0c;感兴趣的可以自己玩一下&#xff1a; https://github.com/MemFire-Cloud/memfirecloud-qa 目前代码主要…...

C# File.Exists与Directory.Exists用法

File.Exists&#xff1a; 用于检查给定文件路径是否存在。如果文件存在&#xff0c;则返回true&#xff0c;否则返回false。 string path“D:\\test\\example.txt” bool exists File.Exists(path); if (exists) {Console.WriteLine("File exists."); } else {Con…...

(深度学习,自监督、半监督、无监督!!!)神经网络修改网络结构如何下手???

修改神经网络结构&#xff0c;我们可以根据这个进行添加&#xff1a; 卷积层&#xff08;Convolutional Layers&#xff09;&#xff1a;标准的卷积层用于提取特征并进行特征映射。 池化层&#xff08;Pooling Layers&#xff09;&#xff1a;用于减少特征图的空间维度&…...

Codejock Task Panel ActiveX Crack

Codejock Task Panel ActiveX Crack ActiveX COM的Codejock任务面板为Windows开发人员提供了一个复杂的Office任务面板&#xff0c;类似于在Microsoft Office和Windows资源管理器中看到的内容。TaskPanel甚至可以用作Visual Studio风格的工具箱。 功能概述 ActiveX COM的Codejo…...

LeetCode 热题 100 JavaScript--141. 环形链表

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…...

文字转语音

键盘获取文字&#xff0c;转化为语音后保存本地 from win32com.client import Dispatch from comtypes.client import CreateObject from comtypes.gen import SpeechLib speakerDispatch(SAPI.SpVoice) speaker.Speak(请输入你想转化的文字) datainput(请输入&#xff1a;)#s…...

让ELK在同一个docker网络下通过名字直接访问

1. docker网络 参考https://blog.csdn.net/lihongbao80/article/details/108019773 https://www.freecodecamp.org/chinese/news/how-to-get-a-docker-container-ip-address-explained-with-examples/ 默认网络有三种&#xff0c;分别是 1、bridge模式&#xff0c;–netbridge(…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...