【MySQL03】【 Buffer Pool】

news2024/11/7 22:33:21

文章目录

  • 一、前言
  • 二、缓冲池(Buffer Pool )
    • 1. 缓冲池的概念
    • 2. LRU List、Free List 和 Flush List
      • 2.1 Free 链表
        • 2.1.1 缓冲页的哈希处理
      • 2.2 Flush 链表
      • 2.3 LRU 链表
        • 2.3.1 简单 LRU 链表
        • 2.3.2 优化后的 LRU 列表
        • 2.3.3 更进一步的优化
    • 3. 脏页的刷新
    • 4. 多个 Buffer Pool 实例
  • 三、重做日志缓冲(redo log buffer)
  • 四、参考内容

一、前言

最近在读《MySQL 是怎样运行的》、《MySQL技术内幕 InnoDB存储引擎 》,后续会随机将书中部分内容记录下来作为学习笔记,部分内容经过个人删改,因此可能存在错误,如想详细了解相关内容强烈推荐阅读相关书籍。


二、缓冲池(Buffer Pool )

1. 缓冲池的概念

InnoDB 存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可将其视为基于磁盘的数据库系统(Disk-base Database)。在数据库系统中,由于CPU速度与磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能。

缓冲池(Buffer Pool )简单来说就是一块连续的内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中这个过程称为将页“FIX”在缓冲池中。下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。

对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。这里需要注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为 CheckPoint 的机制刷新回磁盘。

默认情况下 缓冲池(Buffer Pool )大小只有128M,可以通过 innodb_buffer_pool_size 参数设置。缓冲池(Buffer Pool )中的页类型有:索引页、数据页、undo页、插入缓冲、自适应哈希、InnoDB 存储的锁信息、数据字典信息等,不能简单的认为缓存池只是缓存索引页和数据页,他们只是占了很大一部分而已。1.0.x 开始允许有多个缓冲池实例,每个页根据哈希值平均分配到不同的缓冲池实例,减少了DB的内部资源竞争。如下图:

在这里插入图片描述

InnoDB中为每一个缓冲页都创建了一些控制信息,包括该页所属的表空间属性、页号、缓冲页在 Buffer Pool 中的地址、链表信息等。每个缓冲页对应的控制信息占用的内存大小是相同的,我们把每个页对应的控制信息占用的一块内存称为一个控制块控制块和缓冲页一一对,都存放在 Buffer Pool 中。如下图:

在这里插入图片描述

这里需要注意:

  1. 在 DEBUG 模式下,一个控制块占用缓冲页大约 5% 的大小,正常模式下会更小一些。
  2. 每个控制块都对应一个缓冲页,当剩余空间不足以分配一对控制块和缓冲页的大小时就会产生碎片,如上图。

2. LRU List、Free List 和 Flush List

2.1 Free 链表

在 MySQL 刚启动的时候,需要完成对 Buffer Pool 的初始化过程:首先向操作系统申请 Buffer Pool 的内存空间,然后将其划分为若干对控制块和缓冲页。但此时还没有真正的磁盘页被缓存到 Buffer Pool 中,随着程序的运行会不断有磁盘页被缓存到 Buffer Pool 中。那么就需要记录 Buffer Pool 中的那些缓冲页是可用的:将所有空闲的缓冲页对应的控制块作为一个节点放到一个链表中,称为 Free 链表(空闲链表)。刚完成初始化的 Buffer Pool 中,所有的缓冲页是空闲的。如下:
在这里插入图片描述

从上图可以看到:

  1. Free 链表存在一个基节点,包含链表的头节点、尾节点指针以及链表中节点数量等信息。需要注意这个基节点占用的内存并包含在 Buffer Pool 申请的一大片连续内存空间之内,而是一块单独申请的内存空间。
  2. 每当需要从磁盘加载一个页到 Buffer Pool 中时,就哦那个 Free 链表中取一个空闲缓冲页,并且把该缓冲页对应的控制块的信息填上(即该页所在的表空间、页号等信息),然后把该缓冲页对应的 Free 链接节点(也就是对应的控制块)从链表中移除,表示该缓冲页已经被使用。
2.1.1 缓冲页的哈希处理

当我们需要访问某页中的数据时,就会把该页从磁盘加载到 Buffer Pool 中,如果该页已经在 Buffer Pool 中则直接使用。那么如何定位一个页是否在 Buffer Pool 中?

InnoDB 实际上是通过表空间号 + 页好来定位一个页的,所以可以通过表空间号 + 页号 作为 key,用缓冲页控制块的地址作为 value 来创建一个 哈希表。在需要访问某个页的数据时,先从哈希表中根据表空间号 + 页号 看看是否有对应缓冲页,如果有则直接使用,否则从Free 链表中选择一个空闲的缓冲页,然后把磁盘中对应的页加载到该缓冲页的位置。

2.2 Flush 链表

如果我们修改了 Buffer Pool 中某个缓冲页的数据,此时会造成缓冲页与磁盘页的数据不一致,称为"脏页"(不能修改完一个页的数据就立即刷新到磁盘,不然会严重影响程序性能。所以每次修改完缓冲页后并不是立即刷新而是等到某个刷新时间点后才刷新)。那么InnoDB 就需要记录 Buffer Pool 中哪些页是脏页,以便后续将脏页刷新到磁盘中,因此就出现了一个 FLUSH 链表,凡是被修改过的缓冲页对应的控制块都会作为一个节点加入到这个链表。其结构与 Free 链表相同,这里不再赘述。

注意:某个缓冲页对应的控制块不可能即是 Free 链表的节点又是 Flush 链表的节点。因为如果一个缓冲页时空闲的就不可能是脏页,是脏页就不可能是空闲页。

2.3 LRU 链表

当 Buffer Pool 中不再有空闲的缓冲页时就需要淘汰一部分页。理想情况下是将热点数据所在的页保留,将不常访问的数据所在的页移除,InnoDB 借由 LRU 算法实现了一个链表。

2.3.1 简单 LRU 链表

如果使用传统的 LRU 链表,当需要访问某个页时可以按照如下方式处理链表:

  1. 如果该页不在 Buffer Pool 中,在把该页从磁盘加载到 Buffer Pool 中的缓冲页时,就把该缓冲页对应的控制块作为节点塞到 LRU 链表的头部。
  2. 如果该页已经被加载到 Buffer Pool 中则直接把该页对应的控制块移动到 LRU链表的头部。

即:只要使用到某个缓冲页就将该缓冲页加入到 LRU链表头部,这样 LRU 链表的尾部就是最近最少使用的页,当 Buffer Pool 中空闲缓冲页用完后直接淘汰尾部的页即可。

但这种使用存在问题:

  1. 加载到 Buffer Pool 中的页不一定被用到: InnoDB 存在预读情况,即 InnoDB 认为在执行当前请求时,可能会在后面读取某些页面,就预先将这些页面加载到 Buffer Pool中。这里的预读有分为两种情况:

    • 线性预读:如果顺序访问某个区的页面超过 innodb_read_ahead_threshold (默认56)系统变量的值就会触发一次异步读取下一个区中全部的页面到 Buffer Pool中的请求。
    • 随机预读:当某个区的13个连续的非常热的页(非常热的页:非常热区域的页,下面有介绍)都被加载到 Buffer Pool中,无论这些页面是否是顺序读取,都会触发一次异步读取本区中所有其他页面到 Buffer Pool 中的请求。随机预读可以通过 innodb_random_read_ahead 变量来控制是否开启,默认关闭。
  2. 如果有非常多使用频率偏低的页被同时加载到 Buffer Pool 中,则可能会把那些使用频率非常高的页从 Buffer Poll 中淘汰掉:在执行一些大数据量操作时(如全表扫描)会一次性读取很多页,如果Buffer Pool 容量不足则会将其他页面挤出 LRU 链表。此时全表扫描所加载的页可能并不是热点页,而真正的热点页已经被排挤出 LRU 链表。

2.3.2 优化后的 LRU 列表

因为上述问题,InnoDB 的 LRU 链表做了一定的优化处理:InnoDB 将 LRU链表划分为两部分,访问频率高的数据称为热数据,或者称为 young 区域,另一部分访问频率低的数据称为冷数据,或者称为 old 区域。默认情况 young区域占比是 3/8 (37%),这个比例可以通过 innodb_old_blocks_pct 调整。

经过上述调整后 LRU 链表便可以上面提到的问题做处理了:

  1. 针对预读的页面可能不进行后续访问的优化:当磁盘上某个页面在初次加载到 Buffer Pool 中的某个缓冲页时,该缓冲页的控制块会被放到 old 区域的头部,这样一来,预读到 Buffer Pool 却不进行后续访问的页面就会逐渐从 old 区域逐出,而不会影响 young 区域中的热点数据。
  2. 针对全表扫描时,短时间内大量使用频率低的页面的优化:在对某个处于 old 区域的缓冲页进行第一次访问时,就在它对应的控制块中记录下着访问时间,如果后续的访问时间与第一次的访问时间在某个时间间隔(通过 innodb_old_blocks_time 控制,默认是1s)内,那么该页面就不会从 old 区域移动到 young 区域的头部,否则将他移动到 young 的头部。对于一个页来说,当它从磁盘加载到 LRU 链表中的 old 区域的某个页时,如果第一次和最后一次访问该页面的时间间隔小于1s,则该页不会加入到 young 区域,而对于一次全表扫描,多次访问一个页面(即读取同一个页面中的多条记录)的时间不会超过1s。
2.3.3 更进一步的优化

对于 LRU 链表中的 young 区域的缓冲区来说,每次访问一个缓冲页就要将其移动到 LRU链表的头部开销着实有点大,因为在 young 中的都是热点数据,频繁对 LRU 链表操作并不是明智之举。因此还存在一些优化策略:如只有被访问的缓冲页位于 young 区域1/4 的后面才会被移动到 LRU 链表的头部,这样可以降低调整 LRU 比链表的频率,提高性能。即 在 young 区域 前 1/4 的区域称为 常热区域,在 young 区域 后 3/4 的区域称为 非常热区域

3. 脏页的刷新

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

  1. 从 LRU 建表的冷数据中刷新一部分页面到磁盘 :后台线程会定时从 LRU 链表尾部开始扫描一些页面,如果发现了脏页则将其刷新到磁盘。这种刷新页面的方式称为 BUF_FLUSH_LRU。(缓冲页对应的控制块中存储了该缓冲页是否是脏页的信息,所以扫描 LRU链表可以很轻松获取到某个缓冲页是否是脏页)

  2. 从 Flush 链表中刷新一部分页面到磁盘 :后台线程会定时从 Flush 链表尾部开始扫描一些页面,刷新的速率取决于当时系统是否繁忙,这种刷新方式称为 BUF_FLUSH_LIST。

  3. 有时候后台线程刷新脏页的进度比较慢,导致用户线程在准备加载一个磁盘页到 Buffer Pool 中时没有可用的缓冲页,这时就会尝试查看 LRU 链表尾部,看是否存在可以直接释放掉未修改缓冲页。如果没有则将LRU 链表尾部的一个脏页同步刷新到磁。这种将单个页面刷新到磁盘中的刷新方式称为 BUF_FLUSH_SINGLE_PAGE。在系统特别繁忙时,也可能出现用户线程从 Flush 链表中刷新脏页的情况。

4. 多个 Buffer Pool 实例

Buffer Pool 本质上是向 OS 申请的一块连续的内存。在多线程环境下,访问 Buffer Pool 中的各种链表都需要加锁,在 Buffer Pool 特别大且线程并发量特别高的情况下, 单一的 Buffer Pool 可能会影响到请求速度,因此InnoDB 提供了 innodb_buffer_pool_instances 参数可以修改 Buffer Pool 的数量,需要注意的是InnoDB 规定当 innodb_buffer_pool_size 小于 1G 时设置多个实例时无效的,InnoDB 会默认将 innodb_buffer_pool_instances 改为 1。


三、重做日志缓冲(redo log buffer)

InnoDB 的内存区域除了缓冲池外,还有重做日志缓冲(redo log buffer)。InnoDB 首先将重做日志信息先放入到这个缓冲区。然后按照一定频率将其刷新到重做日志文件。重做日志缓冲一般不需要设置很大,因为一般情况下会有后台线程(默认每秒一次)将其刷新到日志文件中,因此用户只需要保证每秒产生的事务量在这个缓冲大小之内即可。

通常情况下 8M 的重做日志缓冲池足以满足绝大部分场景,因为重做日志在以下情况会刷新到重做日志文件

  1. MySQL 主线程 每秒将重做日志缓冲刷新到重做日志文件。
  2. 每个事务提交时会将重做日志缓冲刷新到重做日志文件。
  3. 当重做日志缓冲池剩余空间小于一半时会将重做日志缓冲刷新到重做日志文件。

四、参考内容

书籍:《MySQL是怎样运行的——从根儿上理解MySQL》、《MySQL技术内幕 InnoDB存储引擎 》

如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

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

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

相关文章

光猫、路由器的路由模式、桥接模式、拨号上网

下面提到的路由器都是家用路由器 一、联网条件 1.每台电脑、路由器、光猫想要上网,都必须有ip地址。 2.电脑获取ip 可以设置静态ip 或 向DHCP服务器(集成在路由器上) 请求ip 电话线上网时期,猫只负责模拟信号和数字信号的转换,电脑需要使…

从零开始:腾讯云轻量应用服务器上部署MaxKB项目(基于LLM大语言模型的知识库问答系统)

使用腾讯云轻量应用服务器部署和使用MaxKB项目 前言 一, MaxKB介绍 MaxKB是基于LLM大语言模型的知识库问答系统,旨在成为企业的最强大脑。它支持开箱即用,无缝嵌入到第三方业务系统,并提供多模型支持,包括主流大模型…

c# 输出二进制字符串

参考链接 C#二进制输出数据_c# 输出二进制 123.5的方法-CSDN博客https://blog.csdn.net/a497785609/article/details/4572112标准数字格式字符串 - .NET | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/standard/base-types/standard-numeric-format-strings#BFo…

医学领域科技查新点提炼方法!---附案例分析

医学领域的查新项目研究范围较广,涉及基础医学、临床医学、中医学、预防医学、卫生学、特种医学等众多与人类健康和疾病有关的科学。查新目的主要包括立项、成果鉴定和报奖,有的期刊投稿也要求作者提供查新报告。 医学领域查新项目的两极化较明显&#…

dynamic多数据源的简单使用

背景 这几天搞了个saas项目,里面用到了多数据和execl模板导出功能, 其实我是经常用到的,但没在博客中写过,最近有点时间,正好稍微写一下。 方便大家使用 这次我先写多数据,execl模板导出下次有空在写。 使…

找好看的简历模板,就上这6个网站。

找好看的简历模板就上这6个网站,免费下载! 1、菜鸟图库 个人简历模板|WORD文档模板免费下载 - 菜鸟图库 站内有超多办公类素材,PPT、world、excel模板都能找到,简历模板有非常详细的分类,风格类型也很多,想…

Kafka 如何基于 KRaft 实现集群最终一致性协调

01 架构概览 Zookeeper 提供了配置服务、分布式同步、命名服务、Leader 选举和集群管理等功能,在大数据时代的开始很多开源产品都依赖 Zookeeper 来构建,Apache Kafka 也不例外。但是随着 Kafka 功能的演进和应用的场景越来越多: 基于 Zoo…

linux命令别名与shell函数

# 修改网卡配置 alias vinetwork"vi /etc/sysconfig/network-scripts/ifcfg-ens33" 1. 方法和调用在同一个文件 # 定义shell函数,返回值通过$?获取 function say_hello(){ echo "hello shell" return 1 } # 使用shell函数 say_hello # 执行脚本后接收返…

怎么解决Hbuilderx的侧边栏不显示文件目录问题

第一步:找到视图 第二步:再视图中找到(显示项目管理器等左边视图)点击就可以了!

时间卷积网络(TCN):概述及与CNN和RNN的比较

TCN 时间卷积网络(TCN):概述及与CNN和RNN的比较1. 时间卷积网络(TCN)定义与特点应用场景 2. 卷积神经网络(CNN)定义与特点应用场景 3. 循环神经网络(RNN)定义与特点应用场…

【Mongodb】Mongodb亿级数据性能测试和压测

一,mongodb数据性能测试 如需转载,请标明出处:https://zhenghuisheng.blog.csdn.net/article/details/139505973 mongodb数据性能测试 一,mongodb数据性能测试1,mongodb数据库创建和索引设置2,线程池批量…

FatFs文件系统移植到MCU平台详细笔记经验教程

0、准备工作 在移植FatFs文件系统前,需要准备好一块开发板,和一张SD卡,且需要已经实现开发板正常的读写SD卡或其它硬件设备。 本文笔记教程中使用的硬件设备是STM32F407VET6开发板(板载SD插槽),配备8G和32G…

【Vue3】vue3快速实现响应式数据恢复初始值。浅拷贝与深拷贝的应用。

有一个经常遇到的场景就是,一个表单最后一列有个编辑按钮,点击编辑按钮之后打开表单弹窗,修改其中的数据,但是如果此弹窗再作为新增弹窗打开的时候,弹窗数据会缓存上次编辑的数据。 在 Vue 3 中,由于引入了…

C语言二级指针、指针数组

一、二级指针 指针变量也是变量,是变量就应有地址,那指针变量的地址存放在哪里?存放在二级指针变量。 此时,*ppa pa,**ppa a。 二、指针数组 指针数组,顾名思义就是存放指针的数组。 数组每个元素为int类…

java自学阶段二:JavaWeb开发45(git学习)

目录: 学习目标git的使用(工作流程、常用命令、idea集成) 一、学习目标: 了解Git基本概念能够了解git的工作流程能够使用Git常用命令熟悉Git代码托管服务能够使用idea操作git 二、git的使用 1)git的概念&#xff1…

学校教学选择SOLIDWORKS教育版的理由

在现代工程和技术教育领域中,计算机辅助设计软件(CAD)已成为不可或缺的教学工具。SOLIDWORKS作为一款功能强大、易于上手的CAD软件,其教育版在学校教学中备受青睐。本文将从多个方面探讨学校教学选择SOLIDWORKS教育版的理由。 一…

堪称2024最强的前端面试场景题,让419人成功拿到offer

前言 2024年的秋季招聘还有两个月就即将到来,很多同学开始思考前端面试中场景题的重要性。这里我提供一些见解和建议来帮助大家准备即将到来的面试。 首先,理解面试中场景题的必要性是至关重要的。与算法或理论问题不同,场景题更贴近实际工…

Linux系统推出VB6开发IDE了?Gambas,Linux脚本编写

第一个Linux程序,加法计算加弹窗对话框,Gambas,linux版的类似VB6的IDE开发环境 一开始想用VB6的Clng函数转成整数,没这函数。 输入3个字母才有智能提示,这点没做好 没有msgbox函数,要用messagebox.warning 如果可以添加函数别名就…

设计软件有哪些?效果工具篇(1),渲染100邀请码1a12

设计师会用到很多渲染效果和后期处理的工具,这里我们介绍一些。 1、AfterBurn AfterBurn是为Autodesk 3ds Max开发的专业级别的体积照明和效果插件。它提供了一系列强大的特效功能,包括烟雾、火焰、云彩等。用户可以利用AfterBurn创建逼真的环境效果&a…

18 - 各赛事的用户注册率(高频 SQL 50 题基础版)

18 - 各赛事的用户注册率 -- 注册率注册用户数/所有用户数 selectr.contest_id,round(100*count(*)/(select count(*) from Users),2) percentage from Register r group by r.contest_id order bypercentage desc,r.contest_id ASC;