写点什么

老面试官问我:LRU 和 Innodb Buffer Pool 有什么关系?

用户头像
极客good
关注
发布于: 刚刚

根据这个特性,LRU 就很合适,Least Recently Used,最近最少使用。根据这个算法就能选择最近最少使用的数据淘汰之~


第五层


===


如果就回答到上面那个程度,还不够,满足不了面试官对你的期望。


我们来想一下普通的 LRU 实现在 buffer 管理这个场景会有什么问题。


下图为先后访问数据 6 和数据 3 之后的情况。



可以看到,被访问的数据会被移到的头部,如果内存不足,会淘汰尾部的数据。


这种实现放在 Buffer Pool 中会有什么问题?


首先你需要了解一个原理:局部性原理


  • 时间局部性:如果一个数据现在被访问了,在近期可能还会被多次访问。

  • 空间局部性:如果一个数据被访问了,那么存储在它附近的数据,很有可能立马


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


被访问。


在硬件、操作系统、应用程序有很多都根据局部性原理做了对应的实现,像磁盘就有预读功能来减少磁盘 I/O。


对应到 Buffer Pool 中也实现了预读的功能。当顺序访问数据页面到达一定的数量或者一个 extent(页面管理的逻辑分区)中有很多页面被加载的时候,Innodb 都会预读页面加载到 Buffer Pool 中。


预读是好事,如果用朴素的 LRU 来实现数据的淘汰就有点问题。


因为预读的数据也会被移动到头部,这样头部原本的热数据就会更靠后了,面临着被淘汰的危机,如果预读的数据有用那没事,如果没用的话,这波就是好心做了坏事。


所以怎么办?


冷热分区,又称老年代和新生代(有 JVM 那味儿了)


Innodb 将缓冲池分为了新生代和老年代。默认头部的 63% 为新生代,尾部 37% 为老年代。



当第一次从磁盘加载数据到 Buffer Pool 时,会将数据放置在老年代的头部,而不是新生代的头部,这样即使有预读功能也不会把前面的热数据给顶一下。


然后下次访问这个数据的时候,会把数据从老年代移动带新生代的头部。


好像已经很完美了?我们再来看另一种情况全表扫描


全表扫描是我们在日常开发中需避免的一种查询,但是有时候就是有需求会全表扫描,或者不经意的错误使用导致全表扫描。


这时候会有很多冷数据被加载到 Buffer Pool 中,被放在老年代,紧接着肯定又会对全表扫描到的数据进行一波处理,那这样这些数据再次被访问,就会被放到新生代的头部,这样就会大量淘汰热区的数据。


一次全表扫描,就替换了很多热数据,降低了缓存的命中率,这波有点伤。


所以怎么办?


加个时间判断


因为全表扫描的数据,大部分紧接着就会被访问,然后之后就没用了,于是 Innodb 设置了一个时间窗口,默认是 1s。


即在老年代数据被再次访问的时间与之前被访问的时间间隔超过 1s,才会晋升到新生代,否则还是在老年代,这样就不会污染新生代的热数据。


这波有点秀吧。


所以 Innodb 针对数据库数据访问的特性,基于分区和时间窗口两个实现改进了 LRU 淘汰缓存页的机制,提高了缓存的命中率,提升了查询效率。


所以,面试官如果问你* LRU 与 Innodb Buffer Pool 之间有什么联系吗?*就用我上面这句话回答即可。


?紧接着等他深入询问,再把上面的缘由解释给他听,这波就 OK 了。


如果面试官问:还有吗?


那下面这个回答可以用上:有。


如果按照普通的 LRU 实现,新生代页面的访问会频繁把数据移动到头部,这个移动是有开销的,而且在很大程度上没有必要,你想想都是热数据自个儿在那移动来移动去的,是不是又是白给?

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
老面试官问我:LRU 和 Innodb Buffer Pool 有什么关系?