前言

  很多小伙伴面试都有被问到MySql数据库的Buffer Pool,主要涉及到Buffer Pool的功能及其对于LRU的优化,接下来就好好聊聊这个Buffer Pool。

1、什么是Buffer Pool

  缓冲池是主内存中的一块区域,用于在InnoDB访问时来缓存表和索引数据。Buffer Pool允许直接从内存访问经常使用的数据,避免每次都去访问数据库,从而加快处理速度,由于内存容量较小且昂贵,因此Buffer Pool的容量不会很大,MySql通过优化LRU算法来扩大Buffer Pool带来的收益。

2、Buffer Pool 底层结构

  LRU全称 Least Recently Used, 也就是最近最少使用的意思,早期用于linux的操作系统中,其中页面置换算法就是LRU的经典应用,将最近最久未使用的页面进行淘汰。常用的LRU算法如下

普通的LRU

  普通的LRU在新增元素时,将元素加入到集合头部,如果加入之前集合已经满了,那么集合尾部的元素将会被移除,如果在集合中的元素有被使用,那么就将这个元素加入到集合头部,上图由于集合满了,1号元素被淘汰了,当集合中的元素再次被使用时,改元素会移动到头部,如下图所示。

  介绍了普通的LRU再来看看Buffer Pool使用的LRU,它是基于普通的LRU基础上进行过优化的,其结构如下图所示。

优化过的LRU

  区别于普通的LRU结构, 它将内部按比例分成2段,前5/8区域被定义为“年轻代”,后3/8区域被定义为“老年代”,每当有新的元素要加入到Buffer Pool中时,不会直接加入到“新生代”的头部,而是会先加到“老年代”的头部,当“老年代”区域的数据被读取时,该数据就会被加入到“年轻代”区域。

  我们可以看到,当“老年代”区域的7号元素被读取时,该元素被加入到“年轻代”区域,而“年轻代”区域尾部的数据则被移动到“老年代”区域的头部位置。

  这么做的好处是什么?首先我们得知道,mysql读取数据时,会对其附近的数据进行预读,当一部分数据被读取时,其附近的数据大概率也会被读取,由此来提高读取数据的效率。

思考问题1:mysql预读的数据并没有被使用怎么办?

  若采用传统的LRU算法,如果MySql预读了大量的数据,而后续没有被使用到,这些数据将直接会被放入到集合的头部,这样就白白浪费了空间,而经过优化的buffer pool在面对这种预读了但是并未使用的数据采用了比较好的策略,首先只要MySql读取数据,这部分数据就会加入到“老年代”区域的头部,一旦“老年代”区域里的数据被使用,这部分数据就会加入到“年轻代”区域的头部,当“年轻代”区域的数据满了,“年轻代”区域尾部的数据就会进入到“老年代”区域头部。每当有数据新加入时,会加入到“老年代”区域的头部,如果“老年代”区域的数据满了,那么就淘汰“老年代”区域尾部的数据,因此优化后的LRU在面对预读失效(数据被读进Buffer Pool但是并没有用上)的情况下仍然有很好的效果。

思考问题2:由于SQL没写好把整张表的数据都读出来了,LRU内数据岂不是全换了?

  当某一个SQL语句扫描出大量的数据时,这些数据先会被加入到”老年代“区域,然后再被添加到”年轻代“区域,这可能导致缓冲池的所有页都替换出去 导致大量的热数据被换出MYSQL性能急剧下降这种情况叫缓冲池污染。

MySQL缓冲池加入了一个“老生代停留时间窗口”的机制:

  • 假设T=老生代停留时间窗口
  • 插入老生代头部的页,即使立刻被访问,并不会立刻放入新生代头部
  • 只有满足“被访问”并且“在老生代停留时间”大于T,才会被放入新生代头部

3、相关的配置

  MySql支持对Buffer Pool的大小的配置、对“老年代”区域和“年轻代”区域的比例的配置以及“老生代停留时间窗口”的配置。

show variables like '%innodb_buffer_pool_size%'; -- 查看buffer pool的大小
show variables like '%innodb_old_blocks_pct%'; -- 查看老年代与新生代的比例 (设置成100就是普通的LRU) 
show variables like '%innodb_old_blocks_time%'; -- 查看时间阈值



4、Buffer Pool与Query Cache的区别

  Query Cache 缓存类似哈希表存储,是将Sql脚本通过Hash作为Key,结果集当做Value 如果每次执行的Sql语句不一样(大小写不一样也算作不一样)那么就不可能能读到缓存。

  Buffer Pool 是将真实的数据进行缓存,任何SQL都有可能直接命中Buffer Pool中的数据 因而减少磁盘IO优化了性能。

5、总结

  通过Buffer Pool的机制可以适当的调节配置来优化当前的一个业务环境,修改SQL语句来尽量让更多的内存来存储缓存热点数据。

参考资料

  • https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html

    ❤️ 谢谢支持
    以上便是本次分享的全部内容,希望对你有所帮助^_^

    喜欢的话别忘了 分享、点赞、收藏 三连哦~。

    欢迎关注公众号 程序员巴士,一辆有趣、有范儿、有温度的程序员巴士,涉猎大厂面经、程序员生活、实战教程、技术前沿等内容,关注我,交个朋友。