Buffer Pool缓存页不够时,如何淘汰缓存?

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 执行CRUD都会将磁盘数据页加载到缓存页,那在加载数据到缓存页时,必然是要加载到空闲缓存页,所以必须要从free中找个空闲缓存页,然后把磁盘数据页加载到该空闲缓存页

Buffer Pool缓存页不够时,如何淘汰缓存?


若BP缓存页不够了,咋办?

执行CRUD都会将磁盘数据页加载到缓存页,那在加载数据到缓存页时,必然是要加载到空闲缓存页,所以必须要从free中找个空闲缓存页,然后把磁盘数据页加载到该空闲缓存页


8.png


随着不断将磁盘数据页加载到空闲缓存页,free中的空闲缓存页会越来越少。最终耗尽free中的空闲缓存页。这时,还要加载数据页到一个空闲缓存页时,MySQL 该何去何从?


若所有缓存页都有数据了,那就无法再从磁盘加载新数据页到缓存页了,则只能淘汰一些缓存页:把一个缓存页里被修改过的数据,刷到磁盘的数据页,然后该缓存页就能被清空, 变回空闲页。然后就能将磁盘的新数据页加载到这刚腾出的空闲页:


那应该把哪个倒霉的缓存页的数据刷盘呢?


缓存命中率


现有两个缓存页:


一个缓存页的数据,经常被修改和查询,都可以操作缓存,不需要从磁盘加载数据,这那缓存命中率就很高。这种高级员工就是啥脏活累活,都会接受。

另一个缓存页里的数据,刚从磁盘加载到缓存页后,被修改和查询过1次,之后100次请求再没有一次是修改和查询该缓存页数据的,那这缓存命中率就有点低了,因为大部分请求还是走磁盘查询数据,他们要操作的数据不在缓存。这种高级员工啥事都干不了,都还得交给低级员工们干事。

很显然,作为领导的你,肯定想把第二个员工裁了吧?


引入LRU,判断哪些缓存页不常用


如何知晓哪些缓存页经常被访问,哪些缓存页很少被访问?


这就需要LRU,Least Recently Used,最近最少使用。这样当缓存页需空出一个刷盘时,通过LRU链表,就能知道最近最少被使用的缓存页。


LRU工作原理


假设从磁盘加载一个数据页到缓存页时,就将该缓存页的描述信息块放入LRU链表头部,那么只要有数据的缓存页,他都会在LRU里,最近被加载数据的缓存页,都会放到LRU链表头部。


假设某缓存页的描述信息块本在LRU链尾,后续你只要查询或修改了该缓存页数据,也要将这缓存页移到LRU链头,即最近被访问过的缓存页,一定在LRU链头。


如此,当无空闲缓存页时候,就能轻易找出最近最少被访问的缓存页去刷盘,即LRU链尾的缓存页,将其刷盘,然后把你需要的磁盘数据页加载到这刚空出的缓存页。


表和行等概念和表空间、数据页的关系


表、列和行,都是逻辑概念,我们只关注DB里有一个表,表里有几个字段,有多少行,但是这些表里的数据

表空间、数据页等是物理概念,在物理层面,表里的数据都放在一个表空间,表空间由一堆磁盘上的数据文件组成,这些数据文件里都存放了表中的数据,这些数据由一个个数据页组织起来

但这样的LRU实际运行时会有问题。


预读


当你从磁盘加载一个数据页时,他可 能会连带着把该数据页相邻的其他数据页,也加载到缓存。


现有两个空闲缓存页,加载一个数据页时,连带着把他的一个相邻数据页也加载到缓存,正好每个数据页放入一个空闲缓存页!


然后呢?实际上只有一个缓存页被访问,另外一个通过预读机制加载的缓存页,其实无人问津,此时这俩缓存页可都在LRU链表前边:


7.png


这时,若无空闲页了,要加载新数据页,就得从LRU链表的尾部将“最近最少使用的缓存页”取出,刷入磁盘,就空出一个缓存页了。


若选择将上图中LRU尾部那个缓存页刷盘,然后清空,合理吗?


他可是之前一直频繁被访问呀,只是这一瞬间,被新加载进的两个缓存页给占了LRU链表前面的位置,尤是第二个缓存页,居然还是通过预读加载来的,其实根本无人访问!而这时将LRU链表尾部缓存页刷盘,肯定不合理,最合理的反而是将那LRU链表第二个通过预读机制加载进的缓存页给淘汰。


MySQL预读触发时机

参数innodb_read_ahead_threshold默认56,即若顺序访问了一个区里的多个数据页,访问的数据页数量超过阈值,就会触发预读,将下个相邻区中的所有数据页都加载到缓 存


若BP里缓存了一个区里的13个连续的数据页,而且这些数据页都是比较频繁会被访问的,此时直接触发预读,把这个区里的其他的数据页都加载到缓存里去。该机制通过参数innodb_random_read_ahead控制,默认OFF关闭。


所以默认主要第一个规则可能触发预读,一下将很多相邻区里的数据页加载进缓存,这些缓存页若突然都放在LRU链表前面,且他们其实并没啥人访问,就会如上图,导致本就在缓存里的一些频繁被访问的缓存页却在LRU链尾。后续一旦要淘汰缓存页,就会将链尾的一些频繁被访问的缓存页给淘汰!


全表扫描


如:


SELECT * FROM xxx


一下子就将表里所有数据页都从磁盘加载到BP。这时他可能会一下子就把这个表的所有数据页都装入各缓存页。此时可能LRU链表中排在前面的一大串缓存页,都是全表扫描加载进来的。若此次全表扫描后,后续几乎没用到这个表里的数据呢?此时LRU链尾可能全都是之前一直被频繁访问的那些缓存页!


然后当需要淘汰缓存页时,就会将LRU链表尾部一直被频繁访问的缓存页给淘汰掉了,而留下之前全表扫描加载进来的大量的不经常访问的缓存页。


为何MySQL设计预读机制,为何有时要把相邻的一些数据页一次性读入到Buffer Pool缓存?


为提升性能。假设你读取了数据页01到缓存页里去,那接下来有可能会接着顺序读取数据页01相邻的数据页02到缓存页,是不是可能在读取数据页02的时候要再次发起一次磁盘IO?


所以为优化性能,MySQL设计了预读机制,即若在一个区内,你顺序读取了好多数据页,比如数据页01~56都被你依次顺序读取了,MySQL觉得你可能接着会继续顺序读取后面的数据页。


此时他干脆提前把后续一大堆数据页(如数据页57~72)都读取到Buffer Pool,后续你再读取数据页60时,就能直接从Buffer Pool里拿到。


但现实骨感,预读的一大堆数据页要是占据LRU链表前面部分,然而可能这些预读的数据页压根儿后续无人用,那这预读机制对性能不增反减。


冷热分离的LRU

于是,为了解决前面的问题,真正MySQL采取冷热数据分离思想改良了 LRU。


之前问题都是因为所有缓存页都混在一个LRU链表才导致的,改良版LRU链表拆为热数据、冷数据两部分,冷热数据比例由innodb_old_blocks_pct参数控制,默认37,即冷数据占37%。这时的LRU链表:


6.png


数据页第一次被加载到缓存时,缓存页会被放在冷区的链表头部。


冷区缓存页何时放入热区?

第一次被加载了数据的缓存页都会不停移动到冷区的链表头部。那为何不放到热区头部呢?


你刚加载了一个数据页到那个缓存页,他在冷区的链表头部,然后立马(在1ms以内)就又被访问了,但之后就再也不访问了呢?难道这种情况也要把这缓存页放到热区头部吗?


所以MySQL设innodb_old_blocks_time参数,默认1000,即1000ms:一个数据页被加载到缓存页之后,在1s后,你又访问了该缓存页,他才会被移到热区的链表头部。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
存储 缓存 算法
缓存淘汰策略
缓存淘汰策略
31 0
|
9月前
|
存储 缓存 算法
缓存淘汰策略:LRU 的设计与实现
缓存淘汰策略:LRU 的设计与实现
156 0
|
3月前
|
缓存 NoSQL 算法
Redis系列-12.Redis的缓存过期淘汰策略
Redis系列-12.Redis的缓存过期淘汰策略
56 0
|
3月前
|
缓存 NoSQL Linux
Redis 缓存淘汰策略
Redis 缓存淘汰策略
59 0
|
4月前
|
存储 缓存 Java
java如何实现一个LRU(最近最少使用)缓存? 要求:设计一个LRU缓存,支持get和put操作。当缓存满时,需要淘汰最近最少使用的元素。要求使用双向链表+哈希表的数据结构来实现,并保证get和put操作的时间复杂度为O(1)。
java如何实现一个LRU(最近最少使用)缓存? 要求:设计一个LRU缓存,支持get和put操作。当缓存满时,需要淘汰最近最少使用的元素。要求使用双向链表+哈希表的数据结构来实现,并保证get和put操作的时间复杂度为O(1)。
28 1
|
6月前
|
缓存 NoSQL 算法
Redis之过期key的淘汰及缓存淘汰策略解读
Redis之过期key的淘汰及缓存淘汰策略解读
|
6月前
|
机器学习/深度学习 缓存 算法
缓存读写淘汰算法W-TinyLFU算法
缓存读写淘汰算法W-TinyLFU算法
|
6月前
|
缓存 NoSQL 算法
Redis学习笔记-缓存容量和淘汰机制核心思想
Redis学习笔记-缓存容量和淘汰机制核心思想
108 0
|
8月前
|
缓存 NoSQL 算法
LRU算法与Caffeine、Redis中的缓存淘汰策略详解与比较
在实际应用中,我们需要考虑数据访问模式、内存限制以及性能需求等因素来选择最合适的缓存淘汰策略。通过深入了解LRU算法及其在不同缓存库中的应用,我们可以更好地优化我们的应用程序的性能。
229 1
|
存储 缓存 算法
【基础篇】4 # 链表(上):如何实现LRU缓存淘汰算法?
【基础篇】4 # 链表(上):如何实现LRU缓存淘汰算法?
130 0
【基础篇】4 # 链表(上):如何实现LRU缓存淘汰算法?

热门文章

最新文章