暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL面试八股文-存储引擎内存结构之Buffer Pool

运维路书 2023-05-30
144


MySQL面试过程中,InnoDB存储引擎的内存结构部分也是一个重要的问题点。今天就着重在这部分拆解一下。


InnoDB存储引擎架构



InnoDB存储引擎架构分为三层


  • 内存结构(In-Memory Structure) 存在于MySQL服务进程中


  • OS Cash  属于内核态内存


  • 磁盘结构 (On-Disk Structure) 存在于文件系统上


本文主要拆解一下内存结构部分,这个是面试环节中比较常问到的问题。


内存结构


Innodb 内存结构的四大核心组件


  • Buffer Pool

  • Change Buffer

  • Log Buffer

  • 自适应哈希索引(Adaptive Hash Index)


四大组件的作用


     Buffer Pool:加速读请求,避免每次数据访问都进行磁盘IO
     Change Buffer:加速写请求,避免每次写入都进行磁盘IO
     Log Buffer:优化redo log 性能,并提供高并发与强一致性
     自适应哈希索引:加速读请求,减少索引查询的寻路路径

Buffer Pool

 

InnoDB缓冲池主要缓存了 表数据和索引数据 。把磁盘中的数据加载到缓冲池中,避免每次访问都进行磁盘IO,提升访问速度。


  由于内存的价格高,容量有限,无法比拟磁盘容量,因此需要把最热的数据放到最近的地方,以最大限度的降低磁盘访问


“MySQL如何管理和淘汰Buffer Pool ?”


  Buffer Pool 以页为单位缓存数据,每个页的大小通常为4K,MySQL为16K


  缓冲池的常用管理算法为LRU,OS 和 memcache都是用这种算法





传统的LRU算法


  将最新加入到缓冲池中的页放到LRU的头部,从而最晚被淘汰, 分为两种情况:


  1. 需要用到的页已经在缓冲池中了,只需要将此页移动到LRU的头部,没有页被淘汰。



  缓冲池中缓存了以上5个页


  现在需要访问4号页,由于4号页已经在缓冲池中了,因此只需要将4号页移动到LRU的头部,尾部的页不会被淘汰。



  2. 页不在缓冲池中,需要将页加入到LRU的头部,从而尾部的页就被淘汰了。


  假如需要访问的页号为50



  (1):页号50 不在缓冲池当中


  (2):页号50加入到LRU头部,尾部的20号页被淘汰


  OS 和 Memcache 都在使用传统的LRU算法





MySQL的LRU算法


  MySQL为了解决预读失效和缓冲池污染的问题对普通的LRU算法进行了优化


Q

什么是预读?

A

磁盘读取,并不是按需读取,而是按页读取。一次至少读取一页,如果未来要读取的数据就在页中,就能够省去后续的磁盘IO,提高效率。


预读失效:


  预读提前把页数据加载到了缓冲池中,但最终MySQL没有从这个页中读取数据,称为预读失效。


  优化预读失效的思路:


  1)让预读失效的页留在缓冲池中的时间尽可能短


  2)真正被读取的页才移动到LRU的头部


  实现方法:


  1)将LRU分为两部分


  新区(new block)


  旧区(old block)


  2)新区旧区首尾相连,新区的尾部连接旧区的头部。


  3)新页加入到缓冲池时,只会加入到旧区的头部


  如果新页预读成功,就是移动到新区的头如果新页预读失败,没有被真正使用,只会比新区的热数据更早的淘汰掉



缓冲区污染:


  当一个质量很差的sql做了全表扫描


  例如:select * from user where name like %abc%;


  此类sql无法命中索引,要进行全表扫描,需要访问大量的页


  1) 把页加载到缓冲池中(插入到旧区头部)


  2) 从页中读出相应的row(插入到新区头部)


  3) row里的name字段与字符串 abc进行比较,符合条件的放入到结果集中


  4) 直到扫描完所有页的所有行


  如此一来,所有页都被加入到了新区的头部,但只会访问一次,大量真实的热数据被换出了缓冲池。


  如何解决缓冲池污染的问题?


  MySQL缓冲池增加了一个旧区停留时间的机制


  1)假设T=旧区停留时间窗口


  2)插入到旧区的头部,并且立刻被访问到,不会立即插入到新区的头部


  3)只有满足 "被访问" 且 "在旧区停留时间大于T" 才被插入到新区的头部


  MySQL缓冲池相关的重要参数:


  innodb_buffer_pool_size:


  缓冲池大小,在内存允许的情况下尽量调大。


  innodb_old_blocks_pct:

  旧区在整个LRU链中占的比例,默认值为37。

       即 新区:旧区=63:37


  innodb_old_blocks_time:

  旧区的停留时间窗口设置,默认值为1000毫秒


总结


  1)缓冲池 Buffer Pool 是一种常见的降低磁盘访问的机制


  2) 缓冲池以页为单位缓存数据


  3)缓冲池常见的管理算法是LRU,OS 、Memcache也使用同样的算法


  4)MySQL加入了 new block 和 old block 解决预读失效的问题,加入old block 停留时间窗口解决缓冲池污染问题



文章转载自运维路书,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论