Mysql中Innodb引擎的BufferPool相关思考

MySQL的InnoDB引擎使用Buffer Pool来优化磁盘I/O,通过LRU算法管理缓存页。为了防止预读失效和缓存池污染,InnoDB将LRU链表分为新生代和老生代,并设置时间窗口机制。脏页通过FlushList进行刷盘管理,确保数据持久化。此外,Buffer Pool在启动时从FreeList获取空闲页,并根据需要淘汰或刷新页面。
摘要由CSDN通过智能技术生成

Mysql中Innodb引擎的BufferPool相关思考

当我们对数据库进行增删改操作时,如果每次都是去硬盘上进行io,那么效率是会非常低的,所以便引入了buffer pool这种缓冲池(内存层面上)来进行优化。

其实相当于我们平常进行的这些操作也是在内存中去处理的。其实有点类似于redis的感觉了。

mysql背后有自己的一套持久化逻辑。(刷脏 各种redo undo binlog 日志等)

为什么不把所有数据都放进缓存中?

因为bufferpool的空间,也就是内存空间是有限的。

undolog日志负责回滚事务

redolog负责的就是数据库的持久化

binlog一般多用于主从同步

有三种链表来维护buffer pool的缓存页

MySQL启动后Buffer Pool会初始化。Buffer Pool也会初始化好N多个空白的缓存页,以及它们的描述数据会被组织成LRU链表以及FreeList 双向链表。

LRU list

其实就是常见的最近最少算法来维护的,但是做了许多的优化。

常见的就是维护了一个链表 有以下两种情况

1.如果命中的缓存页就在链表中,那么将这个缓存页设置成头结点,list中没有缓存页被淘汰

2.如果命中的缓存页不在链表中,那么还是将这个缓存页设置成头结点,将尾节点的缓存页淘汰。

那么问题来了,为什么要对传统的LRU算法进行优化呢?直接这么用不行吗。

会面临以下两个问题。

1。预读失效

2.缓存池污染

何谓预读失效

在预读机制下把别的缓存页也放置到了LRU连表里,却没有预读这些缓存页,那么这些缓存页依旧放置到了LRU链表的头结点附近,需要不断刷新才能被淘汰下去,浪费链表的空间。

如何优化才能防止这个问题呢

思路如下

1.让没有预读到的缓存页尽量少在链表里呆着(减少他们的存在时间,或者说放在链表靠后的位置)

2.只有真正被读取到的缓存页才放在LRU链表的头部位置。

实现方法如下

1.将LRU链表分为两个部分,一部分是新生代(new-sublist),一部分是老生代(old-sublist)

2.将新的页面先放置在老生代中,只有真正被读到的页面才会放在新生代的头部。

但是这样优化过后呢,依旧不能解决缓存池污染的问题。

何谓缓存池污染

当我们执行了一条需要大量扫描数据库的语句时,(比如select * from 表名 where 字段 like “%xxx%”),这条语句由于不会走索引需要全表扫描,然后需要读取大量的缓存页塞到LRU链表里面去,这个时候仅仅是放在了老生代中,但是读取缓存页中的row的时候,就会把这些缓存页放置在新生代的头部。这种操作会导致所有的页都被扔到了LRU链表里,但是仅仅只是被访问了一次就可能再也不会访问了。真正的高频热点数据会被大量置换出去。

如何解决缓存池污染的情况呢

mysql在老生代做了一个时间窗口机制的优化。当新的缓存页被加入到老生代的时候,只有当他们在老生代中停留时间超过xxx秒之后依旧被访问读取,才会将这些缓存页添加到新生代头结点位置。

比如刚才举得那个例子,这种一次性的全表扫描都是添加进入LRU链表之后,直接进行访问的,所以这些缓存页依旧停留在老生代中,新生代中的热点数据不会被替换。

Free List

在数据库刚启动的时候,LRU链表还是空的,这个时候如果我们需要把磁盘中的数据页缓存到buffer pool的话,我们就需要从Free List中去选择空闲的缓存页。如果有的话,就将该缓存页从Free List中删除,放入到LRU List中。如果Free List里面没有空闲的缓存页,这个时候就会根据LRU相关算法,将LRU列表末尾的缓存页淘汰掉,将内存空间分配给新的页面。

Flush List

AKA,BufferPool是存在于内存当中的,为了避免频繁的磁盘io的效率低下而产生的。但是这些buffer pool里面的数据终究还是要做持久化的,也就意味着必须得有刷盘(刷脏相关的机制去维护持久化的结果)。

于是就有了Flush List的出现。每个在LRU List中被改变了的缓存页,都会被叫做脏页,然后这些脏页也维护起了一个类似于上文FreeList一样的一个双向链表。

那么这时候就涉及到了,什么时候把Flush List中的脏数据刷回磁盘呢,

1.mysql关闭的时候,会把所有的脏页都刷新回磁盘

2.master thread会按照设定,定时的将buffer pool中的脏页刷新回磁盘

3.redo log如果即将满了或者意外挂掉了不能用,也会触发刷新机制

4.脏数据也太多的话,根据 innodb_nax_dirty_pages_pct 这个参数设置的比例进行刷盘。(但是默认值为0,以防启动的时候疯狂刷盘)

总结

(1)缓冲池(buffer pool)是一种常见的降低磁盘访问的机制;

(2)缓冲池通常以页(page)为单位缓存数据;

(3)缓冲池的常见管理算法是LRU,memcache,OS,InnoDB都使用了这种算法;

(4)InnoDB对普通LRU进行了优化:

  • 将缓冲池分为老生代和新生代,入缓冲池的页,优先进入老生代,页被访问,才进入新生代,以解决预读失效的问题
  • 页被访问,且在老生代停留时间超过配置阈值的,才进入新生代,以解决批量数据访问,大量热数据淘汰的问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值