InnoDB的Buffer Pool

news2024/12/23 1:31:18

前置概念:一个数据页16KB,一个数据页可能有多个记录,即使我们只需要访问一条记录,需要把整个数据页加载到内存中,加载到内存后不是直接释放,而是缓存到内存当中(当然对于buffer pool的缓存是在存储引擎层的发生在优化器之后,而mysql的查询缓存和buffer pool不是一个东西,查询缓存发生在最开始的时候)。

buffer pool的概念

提出buffer pool是为了缓存磁盘中的页,在mysql服务器启动的时候就向操作系统申请一片连续的内存,这一片的内存就是buffer pool,也就缓冲池。

默认情况下 buffer pooll只有128M大小,我们可以在启动服务器的时候配置innodb_buffer_pool_size参数的值。

buffer pool内部组成

buffer pool中的缓存页大小和磁盘中数据页相同16KB。

1)每个缓存页对应一个控制块,控制块是什么呢,描述缓存页的表空间编号,页号,存储也在buffer pool中的地址,一些所信息等。

2)每个缓存页对应的控制信息占用的内存大小是相同的。在mysql5.7中控制块占用808字节。

3)控制块和缓存页都存放到buffer pool中,控制块放在buffer pool的前边,缓存也放在buffer pool的后面。

free链表和flush链表

1、free链表

首先mysql服务器初始化,向操作系统申请一段连续的内存空间,然后把他划分成若干对控制块和缓存页,此刻缓存页都还没有用到。随着程序的运行会不断地有磁盘的页 被缓存到buffer pool中,那么往哪个缓存页中放呢?换句话说mysql是怎么知道哪个缓存页是空闲的呢?

链表!在存储数据的磁盘中,也就是文件系统的表空间中,管理数据页、区都是用的链表。

管理缓存页也是用链表,两个链表,一个是free链表,一个是flush链表。

顾名思义free链表中全是空闲的缓存页。另外我们呢要注意一点链表管理的是控制块,也就是说控制块作为一个节点放到链表中,控制块管理缓存页。

注意:基节点占用的不是buffer pool而是单独申请的一块内存空间。

流程:当需要从磁盘加载一个页到buffer pool中就从free链表中去一个空闲的缓存页,并且把该缓存也的控制块信息天上。之后把缓存页对应的控制块的free链表节点从链表中移除表示该缓存页已经使用了。

缓存页的哈希处理

前面说了,当我们要访问某个也的数据时,就会把该页从磁盘加载到 buffer pool,如果该页已经在buffer pool中的话就直接使用就可以了。那mysql怎么知道该页在不在buffer pool中呢?难道是遍历一遍链表,no遍历太慢。

hasn结构,我们是根据表空间号+页号定位一个页的。相当于表空间号+页号是一个key,缓存页就是对应的value。

2、flush链表

当修改了某个缓存页中的数据,那他就和磁盘的数据页不一致了,这时候的缓存页就叫脏页。

如果每一次有脏页产生就立刻同步到磁盘上对应的页上,那性能非常低。所以我们呢不着急立刻修改同步磁盘上。而是存起来,到未来的某个时间点进行同步。这个管理脏页的数据结构还是链表,flush链表中放的就是被修改的脏页。

LRU链表的管理

众所周知,buffer pool对应的内存大小是有限的,可定会满,满了就清,那怎么进行清理呢?

我们要留存的数据,必定是热点数据,或者说必须缓存命中率必须越高越好。

参考微信聊天列表,排在前面的都是频繁使用到的。排在后面的都是很久不联系的。用什么样的数据结构来维护这个“微信列表”链表呢?LRU链表

简单LRU链表介绍

最近最少使用的原则去淘汰缓存页。当我们需要访问某个页的时候,LRU链表发生了这个情况:

1)如果该页不在buffer pool,在把该页从磁盘加载到buffer pool中的缓存页时,就把该缓存页对应的控制块作为节点塞到LRU链表的头部。

2)如果该页已经在buffer pool中,直接把控制块移动到头部。

划分区域的LRU链表

上面介绍的简单LRU链表mysql并没有应用,而是使用的划分区域的LRU链表。

为什么不使用简单的LRU链表呢?简单的LRU链表有什么问题呢?两种情况不适用。

情况一:预读(还没用使用到就从磁盘读到buffer pool)

        线性预读

        如果顺序访问某个区的页面超过了innodb_read_ahead_threshold(默认为56,一个区64个页,超过54就预读下一个区的全部页面)系统变量的值,就会触发一次异步读取下一个区中全部的页面到buffer pool的请求。

        随机预读

        如果buffer pool已经缓存了某个区的13个连续的页面,不论这些页是否时顺序读取的,都会出发一次一部读取本区全部页面的buffer pool请求。

        预读的问题

        预读的页面放到了链表的头部,有很多页面可能会用不到 ,降低了缓存命中率。

情况二:全表扫描

        很好理解,全表扫描会大量读取页面,但是全表扫描发生的概率不大,所以简单LRU缓存的页没有大用,降低了缓存命中率。

总结

上面的两种情况反映出了两个问题:

1)加载到buffer pool的页不一定被用到

2)用的少的页面把热点页面挤掉。

划分LRU链表的结构

为了解决这两种情况,InnoDB把LRU量表分为两段,分别是热数据段和冷数据段。

注意:InnoDB时按照某个比例将LRU链表分为两半的,也就是说随着程序运行,某个节点的区域会发生变化。

复杂LRU链表的优化

        针对预读的优化

                其实并没有对预读进行优化,只是InnoDB规定当磁盘上的某个页面初次加载到buffer pool中的某个缓存页时,该缓存页对应的控制块会被放到old区域的头部,如果后续不进行访问,就会从old区域逐出。从而不会影响到young区域中的缓存页。

        针对全表扫描的优化

                在mysql中规定每次区页面中读取一条记录时,都算时访问一次页面,而一个页面可能 会包含很多条记录,也就是说读取完某个页面的记录就像当于访问这个页面好多次。这样按理来说young区域会被挤出很多热点数据。

                InnoDB为了解决上面的问题是这么规定的:在对某个在old区域的缓存页进行第一次访问的时候就在他对应的控制块中记录下这个访问时间,如果后续的访问时间于第一次的访问时间在某个时间间隔内,就那么该页面就不会被从old区域移动到young区域的头部,否则就会被移动到young区域的头部。

复杂LRU链表的进一步优化

        这次优化时针对young区域的缓存页进行优化的。

        young区域有一个问题,因为被经常访问,那么他会经常移动到头节点,这样的开销太大了。

        针对这个问题进行优化:

                只有被访问的缓存页位于young区域的1/4后面,才会被移动到LRU链表头部,这样能降低调整LRU链表的牝鹿,从而提升性能。换句话说,某个缓存页对应的节点在young区域的1/4中,访问也不会移动到LRU链表头部。

刷新脏页到磁盘

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

        从LRU的冷数据中刷新一部分页面到磁盘。

                后台线程会定时从LRU链表尾部开始扫描页面,发现脏页就会刷新到磁盘。

        从flush链表中刷新一部分页面到磁盘

                后台线程也会定时从flush链表中刷新一部分页面到磁盘。刷新的速率取决于当时系统是不是很繁忙。

        思考:

        有两个线程,后台线程和用户线程。用户线程在准备加载一个磁盘也到buffer pool时没有可用的缓存页,这时候就会从LRU链表尾部直接释放掉为修改的页面,如果没有未修改的页面,就不得不将LRU链表尾部的一个脏页同步刷新到磁盘。

总结

1)InnoDB想操作系统申请一段连续的内存空间作为缓存

2)innodb_buffer_pool_size参数可以调整buffer pool的大小

3)buffer pool有两个部分,控制块和缓存页。每个控制块和缓存页都是一一对应的。

4)innodb使用了使用链表来管理buffer pool。free链表、frush链表、LRU链表。

5)链表中的节点都是控制块。

6)为了快速定位某个也是否被加载到buffer pool,使用了hash算法,使用空间号+页号作为key,缓存页作为value,建立hash表。

7)在buffer pool中修改的页面叫脏页,脏页不是立刻刷新到磁盘,而是加入到flush列表中,之后某一时刻同步刷新到磁盘

8)LRU链表分为young和old两个区域,首次加载到buffer pool的页会被放到old区域的头部,在某个时间间隔内访问该页不会移动到young区域头部,在没有可用的缓存页的时候首先会淘汰掉old区域的一些页,如果是脏页会刷新到磁盘再淘汰。

                

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1405138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

layui 自定义日期选择器今日、昨日 、本周、本月、上个月等

1、layui 日期选择器 laydate日期选择器 <div class"layui-input-inline"><input class"layui-input" id"dateTime" placeholder"日期范围"> </div><script> layui.use([laydate], function () {laydate.ren…

为什么MOS管很容易失效?有哪些失效?

在电子元件中&#xff0c;金属-氧化物半导体场效应晶体管&#xff08;MOS管&#xff09;是独特且重要&#xff0c;然而相比其他元件&#xff0c;MOS管很容易失效&#xff0c;导致电路无法正常运行&#xff0c;因此工程师必须查找原因并解决问题。 1、MOS管为什么很容易失效&…

windows vscode jsoncpp cmake c++ 构建项目

jsoncpp的编译和使用推荐文章&#xff1a;jsoncpp的编译和使用 | 爱编程的大丙 (subingwen.cn)https://www.subingwen.cn/cpp/jsoncpp/从这个链接下载jsoncpp-master&#xff1a;https://github.com/open-source-parsers/jsoncpp 可以把这个文件夹名字改成jsoncpp&#xff0c;…

c++:string相关的oj题(415. 字符串相加、125. 验证回文串、541. 反转字符串 II、557. 反转字符串中的单词 III)

文章目录 1. 415. 字符串相加题目详情代码1思路1代码2思路2 2. 125. 验证回文串题目详情代码1&#xff08;按照要求修改后放到新string里&#xff09;思路1代码2(利用双指针/索引)思路2 3. 541. 反转字符串 II题目详情代码1思路1 4. 557. 反转字符串中的单词 III题目详情代码1&…

[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

【JAVA】我和我的第一个“对象”相遇

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-zAjv1fTLGQmnqncy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

vue2面试题:什么是双向数据绑定

vue2面试题&#xff1a;什么是双向数据绑定 回答思路&#xff1a;1.什么是双向绑定-->2.双向数据绑定的原理-->3.如何实现双向数据绑定1.什么是双向绑定2.双向数据绑定的原理3.如何实现双向数据绑定来一个构造函数&#xff1a;执行初始化&#xff0c;对data执行响应化处理…

基于Python实现人脸识别相似度对比

目录 引言背景介绍目的和意义 人脸识别的原理人脸图像获取人脸检测与定位人脸特征提取相似度计算 基于Python的人脸相似度对比实现数据集准备人脸图像预处理特征提取相似度计算 引言 背景介绍 人脸识别技术是一种通过计算机对人脸图像进行分析和处理&#xff0c;从而实现自动识…

性能优化(CPU优化技术)-NEON 介绍

「发表于知乎专栏《移动端算法优化》」 本节主要介绍基本 SIMD 及其他的指令流与数据流的处理方式&#xff0c;NEON 的基本原理、指令以及与其他平台及硬件的对比。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;…

[嵌入式软件][启蒙篇][仿真平台] STM32F103实现串口输出输入、ADC采集

上一篇&#xff1a;[嵌入式软件][启蒙篇][仿真平台] STM32F103实现LED、按键 文章目录 一、串口输出(1) 简介(2) 示例代码(3) 仿真效果 二、串口输入(1) 简介(2) 示例代码(3) 仿真效果 三、ADC采集(1) 简介(2) 采集电压(3) 示例代码&#xff08;电压&#xff09;(4) 仿真效果 …

c++小技巧14:多线程

1.前言 最近&#xff0c;被期末考试AK的zzb在回顾以前的代码时&#xff0c;无意看到一个问题: 请问: 大佬能解释一下怎么同时运行两个cfor循环吗&#xff1f; 就比如说游戏里你一边出招电脑也能出招这种的 当时&#xff0c;zzb是用的kd来解决(详见小技巧2) 而现在&#xff0c…

GO 的那些 IDE

文章目录 支持哪些功能快捷键代码高亮代码格式化代码提示导航跳转代码调试构建编译其他功能 GO有哪些IDEGolandVS CodeVim GOSublime TextAtomLiteIDEEclipse 总结 “程序员为什么要使用 IDE”&#xff0c;在一些社区论坛&#xff0c;经常可以看到这样的提问。关于是否应该使用…

AI创作之旅:探索提示工程的奇妙世界

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在当今信息爆炸的时代&#xff0c;人工智能的发…

ELK分离式日志(2)

目录 一.FilebeatELK 部署 开台服务器&#xff08;192.168.233.50&#xff09;下载fliebeat&#xff1a; 安装nginx后查看下日志文件&#xff1a; 设置 filebeat 的主配置文件: 关闭logstash&#xff0c;检测文件&#xff1a; 在50节点上启动filebeat&#xff1a; 访问页…

前端基础(三十八):iframe通信、浏览器跨窗口通信

iframe通信 - MessageChannel <!-- index.html --> <h3>MessageChannel</h3> <input id"input" type"text" oninput"handleInput(this.value)" /> <hr /> <iframe src"./demo.html"></iframe&…

Java 数据结构篇-实现红黑树的核心方法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 红黑树的说明 2.0 红黑树的特性 3.0 红黑树的成员变量及其构造方法 4.0 实现红黑树的核心方法 4.1 红黑树内部类的核心方法 &#xff08;1&#xff09;判断当前…

k8s中服务器容器tcp连接数量优化

netty的http1服务器在运行一段时间后会无法提供服务&#xff0c;返回客户端socket hang up 使用apipost测试抓包显示三次握手后被reset 客户端使用了大量短连接&#xff0c;如果能改成长连接就会消耗更少的连接&#xff0c;但是客户端逻辑无法掌控&#xff0c;只能修改服务器。…

网络安全概述---笔记总结

网络安全概述 网络安全---Cyberspace security 2003年美国提出网络空间的概念 --- 一个由信息基础设施组成的互相依赖的网络。我国官方文件定义&#xff1a;网络空间为继海&#xff0c;陆&#xff0c;空&#xff0c;天以外的第五大人类活动领域 发展阶段&#xff1a; 通信保…

学习STM32,该用哪款开发工具?

有很多初学者在问&#xff1a;学习STM32&#xff0c;该用哪款开发工具&#xff1f; 我首先说一下我的观点&#xff1a; 1.没有最好&#xff0c;只有适不适合&#xff0c;适合自己的才是最好的。 2.开发工具很多&#xff0c;各有各的特点&#xff0c;有优点肯定也有缺点。 本文…

MySQL InnoDB 底层数据存储

InnoDB 页记录Page Directory记录迁移 页 是内存与磁盘交互的基本单位&#xff0c;16kb。 比如&#xff0c;查询的时候&#xff0c;并不是只从磁盘读取某条记录&#xff0c;而是记录所在的页 记录 记录的物理插入是随机的&#xff0c;就是在磁盘上的位置是无序的。但是在页中…