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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Mysql专栏 - 缓冲池的内部结构(二)

前言


这是mysql专栏的第四篇,上一个小节我们了解了如何通过flush list存储所有的脏页数据,这一节我们来继续介绍缓冲池的内部结构LRU链表。


概述


缓冲池的大小是固定的,缓冲池当然不是永远都驻留在缓冲池的,但是空闲缓冲页不够情况下如何处理呢?本节将会讨论缓冲池重要的淘汰机制:LRU的淘汰机制,后续会介绍mysql的冷热数据分离特性,最后将给出几个思考题回顾整个内容。


缓存页的刷新机制 - LRU淘汰缓存页



Buffer pool 中的缓存页不够怎么办?


经过上一节的讨论,当执行器发来了增删改查的请求的时候会从磁盘文件读取对应的数据块到缓冲池当中,之前提到过缓冲池不是无限的,默认情况下最多只有128m,一旦所有的缓存页都被加载就意味着free list内部没有空闲的缓存页,当所有的空闲缓存页被分配完了,这意味着缓冲池已经无法再分配缓冲页了,但是我们还想把数据页加载到缓存池怎么办?

如果我们想要加载新的缓存页也十分简单,只要淘汰一些不常用的缓存页即可。


淘汰那个缓存,淘汰谁?


淘汰缓冲页就是把缓冲池里面的某个缓冲页刷新到磁盘(必须先刷新数据到磁盘)然后把对应的缓存页删除即可。接着再把新的数据页的内容加载到缓冲池即可。那么究竟要把那个缓存页刷新到磁盘呢?


缓存命中率


缓存命中率很好理解,假设有两个缓存页,第一个缓存页在100次请求中查询和修改了30次,意味着这个缓存页的命中率为30%。并且缓存命中率不错。第二个缓存页则在100次内只操作了1,2次,这意味着缓存命中率很低,所以不用说,肯定是淘汰第二个。


LRU链表淘汰算法


为了判断哪些缓存页经常被访问,哪些缓存页很少被访问。mysql引入一个新的LRU链表,LRU 就是least recently used,也就是最少使用的意思。通过这个LRU链表,我们就可以知道那个缓存页是最少使用的,当需要一个新的缓存页的时候就可以通过一个LRU链表知道那个缓存页使用频率最低并将其刷新到磁盘文件并且移除。

当某个缓存页被操作的时候,就会找到LRU列表对应的节点加入进去,需要淘汰一个缓存页,就找到LRU列表的尾部进行淘汰(输入磁盘并且从缓冲池情况,同时free list增加一个空闲的描述信息节点),因为最后一个节点肯定是使用频率最低的。


下面我们根据之前文章的结构图,补充一个LRU链表,最后的结构图内容如下:


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


简单的LRU链表存在哪些问题?



当Free list没有可用的空闲节点的时候,需要从LRU链表的尾部刷新一个缓存块到磁盘并且清空这个缓存块把位置让给新的数据块。

但是mysql的LRU的链表有许多的特性。那么在介绍新特性之前,我们来看下普通的LRU链表会带来哪些问题

简单的LRU链表有哪些问题呢?


1. 预读:


首先这样的LRU有一个重大的隐患:预读,比如现在存在两个空闲缓存页,加载一个数据页之后,同时会把相邻的数据页页加载到缓存区,正好每一个数据页放入一个空闲缓存页。意味着实际上只有一个缓存页被访问了,另一通过预读的机制加载的缓存页,但是这两个都被放到了链表的最前面,最后,预读会造成尾端的缓存页被错误的删除,然而正确的做法是删除第二个被预读缓存的缓存页

接着我们来看看,到底哪些情况下会触发MySQL的预读机制呢?


(1) 有一个参数是**innodb_read_ahead_threshold**,他的默认值是56,意思就是如果顺序的访问了一个区里的多个数据页,访问的数据页的数量超过了这个阈值,此时就会触发预读机制,把下一个相邻区中的所有数据页都加载到缓存里去。
(2) 如果Buffer Pool里缓存了一个区里的13个连续的数据页,而且这些数据页都是比较频繁会被访问的,此时就会直接触发预读机制,把这个区里的其他的数据页都加载到缓存里去
这个预读机制是通过参数**innodb_random_read_ahead**来控制的,他**默认是OFF**,也就是这个规则默认是关闭的


吐槽:预读的机制有点类似机器磁盘的顺序访问操作。


2. 全表扫描


全表扫描相信学过数据库的都知道这个理念,。从底层来看一个全表扫描的查询可能会把表所有的数据页放到buffer pool里面,最终可能会把一整个表的数据页加载到缓存页里面,LRU的前面一大串页都是全表查询的数据页。这会导致尾部淘汰的缓存页是一些经常用到的缓存页,而留下的都是不怎么使用的数据块,这样缓存的命中率会大大降低,导致整个mysql的性能十分差。


冷热数据分离的LRU



解决上面的两个问题激素使用冷热分离的LRU,冷热分离的意思是说按照一定的比例把整个链表分为热数据和冷数据,mysql当中由 innodb_old_blocks_pct 参数进行控制,默认是37, 意味着冷数据占了37%,热数据占了63%


冷热数据如何使用


第一次加载的时候缓存页的数据会放到哪一个位置?稍微琢磨一下不难得出答案那就是:冷数据的头部。第一次把数据页加入到缓存页默认会放到冷数据的头部。


冷数据什么时候进入热数据


冷数据进入热数据肯定是需要一定的缓存命中率的,所以是按照缓存命中率判定的,是这样么?其实不是的这样想是错的,因为这很难作为一个权衡条件。其实冷热数据是按照第一次加载缓冲页1S之后如果你还是访问了这个数据页,那么这个数据就会升级为热数据也就是放到热数据的头部,另外这个参数是根据innodb_old_blocks_time这个参数进行判断的,默认设置的参数就1000(毫秒)也就是1s。


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


缓存页不够如何淘汰缓存


冷热分离之后淘汰缓存页就简单了,直接找到冷数据的尾部缓存页,把这些缓存文件刷到磁盘文件之后可以直接清除,无需担心他们这些数据可能是频繁访问的数据。


冷热分离如何解决预读和全表查询问题


当预读和全表查询加载出一大堆的数据之后,会发现他们的数据其实都在冷数据的头部的,但是如果1S之后依然频繁访问的冷数据,则会不断的放到热数据的头部去的,但是一大段读取出来的冷数据,由于只访问了一次之后就再也没有访问过了。所以是没有什么关系的。


预读和全表加载的数据,会进入热数据区域么?

如果仅仅是一个全表扫描的查询,此时你肯定是在1s内就把一大堆缓存页加载进来,然后就访问了这些缓存页一下后就完事了,通常这些操作1s内就结束了。也就是说一个全表查的数据许多的临时数据是会直接放到冷数据页的。但是如果这部分数据在1S之后再次被访问,才会升级为热数据。但是“全表查最好尽量避免,错误的热数据也是隐患”。


总结:


到现在为止我们已经彻底搞定了LRU链表的设计机制,刚加载数据的缓存页都是放冷数据区域的头部的,而1s过后被访问了才会放热数据区域的头部,热数据区域的缓存页被访问了,就会自动放到头部去。这样的话实际上冷数据区域放的都是加载进来的缓存页,最多在1s内被访问过,之后就再也没访问过的冷数据缓存页!而加载进来之后在1s过后还经常被访问的缓存页都放在了热数据区域里,他们进行了冷热数据的隔离!这样的话在淘汰缓存的时候,一定是优先淘汰冷数据区域几乎不怎么被访问的缓存页的,最后这种冷热数据分离的思想是十分值得借鉴的一种设计思想。


思考题:



为什么MySQL要设计预读这个机制?


为什么MySQL要设计预读这个机制? 他加载一个数据页到缓存里去的时候,为什么要把一些相邻的数据页也加载到缓存里去呢?这么做的意义在哪里? 是为了应对什么样的一个场景?


为了优化性能引入了预读的机制,顺序读取之后可能会出现后续的顺序读取,所以加载后面的数据页也是合理的,但是理想情况下这种预读可能是好心办坏事,一旦这些预读的页没有加载出来,就是在捣乱了。所以这也是为什么mysql默认情况下是这个规则关闭的(设计的确实不太好)


为什么要设置1S的规则


其实这个规则是针对 全表查询而设置的,因为全表查询会一次性加载出很多的数据页到缓冲池,但是这些数据在短时间可能被误判为热数据,设置1S是因为大部分的全表查询基本都能在1S内完成(当然海量数据除外)。


redis的冷热数据问题


对于这种缓存中同时包含冷热数据的场景,如果你是在Redis中你的业务系统放了很多缓存数据,其中也是冷热数据都有的,此时可能会有什么问题?那么针对这样的一个问题,你是否可以考虑在你自己的缓存设计中,运用冷热隔离的思想来优化重构呢?

肯定是存在问题的,因为假设我们有1亿个商品,然后查询商品不在缓存里面就放到缓存里面,大量不经常访问的数据会在redis里面占用的很多内存但是没有人访问。所以这时候热数据的预加载就会用上的了,统计哪些商品访问的次数最多。然后晚上启动定时任务,把热数据放到redis里面,第二天加载的时候就会优先加载热数据了。


写在最后


如果觉得有帮助希望不忘点个赞给予支持,你的支持和鼓励是我最大的动力,最后欢迎关注个人微信公众号:懒时小窝

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
传感器 机器学习/深度学习 编解码
图像配准:基于 OpenCV 的高效实现
在这篇文章中,我将对图像配准进行一个简单概述,展示一个最小的 OpenCV 实现,并展示一个可以使配准过程更加高效的简单技巧。
|
9天前
|
机器学习/深度学习 人工智能 JSON
构建AI智能体:二十八、大语言模型BERT:原理、应用结合日常场景实践全面解析
BERT是谷歌2018年推出的革命性自然语言处理模型,采用Transformer编码器架构和预训练-微调范式。其核心创新在于双向上下文理解和掩码语言建模,能有效处理一词多义和复杂语义关系。BERT通过多层自注意力机制构建深度表示,输入融合词嵌入、位置嵌入和段落嵌入,输出包含丰富上下文信息的向量。主要应用包括文本分类、命名实体识别、问答系统等,在搜索优化、智能客服、内容推荐等领域发挥重要作用。
301 10
|
10月前
|
机器学习/深度学习 供应链 搜索推荐
优化销售预测:6种模型适用的场景与实战案例
不同行业的销售预测采用什么模型比较好?3分钟了解6种销售预测模型,以及适用行业场景。
2930 2
优化销售预测:6种模型适用的场景与实战案例
|
数据采集 机器学习/深度学习 自然语言处理
Python实现文本分类的方法详解
本文详细介绍了Python实现文本分类的方法,包括数据清洗、特征提取、模型训练和预测等步骤。通过代码示例和实际案例,帮助读者快速掌握文本分类的基本原理和实现方法。
320 1
|
机器学习/深度学习 分布式计算 算法
Spark中的二分类与多分类问题的解决
Spark中的二分类与多分类问题的解决
|
机器学习/深度学习 人工智能 算法
一文尽览!弱监督语义/实例/全景分割全面调研(2022最新综述)(下)
今天分享一篇上交投稿TPAMI的文章,论文很全面的调研了广义上的弱监督分割算法,又涵盖了语义、实例和全景三个主流的分割任务。特别是基于目标框的弱监督分割算法,未来有很大的研究价值和落地价值,相关算法如BoxInst、DiscoBox和ECCV2022的BoxLevelset已经证明了,只用目标框可以实现可靠的分割性能。论文很赞,内容很扎实,分割方向的同学一定不要错过!
一文尽览!弱监督语义/实例/全景分割全面调研(2022最新综述)(下)
|
机器学习/深度学习 数据采集 人工智能
基于TextCNN实现文本分类
本文参考Yoon Kim的论文"Convolutional Neural Networks for Sentence Classification",实现TextCNN卷积神经网络进行文本分类。
568 0
基于TextCNN实现文本分类
|
机器学习/深度学习 算法 数据可视化
利用Python实现简单的文本分类器
本文介绍了如何使用Python编写一个简单的文本分类器,通过基于词袋模型和朴素贝叶斯算法的方法实现对文本进行分类。通过示例代码和详细说明,读者可以了解如何构建一个能够自动对文本进行分类的程序,并在实际应用中使用这种技术。
|
机器学习/深度学习 传感器 人工智能
首篇!最全的全景分割综述(RGB图像/医学图像/LiDAR)(上)
本文对现有的全景分割方法进行了第一次全面的综述。因此,基于所采用的算法、应用场景和主要目标的性质,对现有全景技术进行了定义良好的分类。此外,还讨论了全景分割在通过伪标记标注新数据集中的应用。接下来,进行消融研究,以从不同角度了解全景方法。此外,还讨论了适用于全景分割的评估指标,并对现有解决方案的性能进行了比较,以了解最新技术并确定其局限性和优势。最后,阐述了当前主题技术面临的挑战以及近期吸引大量关注的未来趋势,这可以作为未来研究的起点。
首篇!最全的全景分割综述(RGB图像/医学图像/LiDAR)(上)
|
机器学习/深度学习 自然语言处理 算法
Python数据分析(4):jieba分词详解
Python数据分析(4):jieba分词详解
1429 0
Python数据分析(4):jieba分词详解