InnoDB Buffer Pool

定义

对于InnoDB存储引擎,不管用户数据还是系统数据都是以页的形式存储在表空间进行管理的,其实都是存储在磁盘上的。

当InnoDB处理客户端请求,需要读取某页的一条记录时,就会将这个页中的所有数据加载到内存中,再进行读写操作,当读写操作完成后,不是先将内存空间释放,而是将其缓存起来,当下次有同样的请求时,可以省去磁盘IO的开销。

而InnoDB缓存这些页的内存就叫做Buffer Pool,(5.7.5v之前这是一块连续的内存,可以在配置文件中以innodb_buffer_pool_size动态修改其大小,这之后,以chunk为单位想操作系统申请空间,Buffer Pool由若干个chunk组成,一个chunk就是一片连续的空间)如果Buffer Pool大小大于1G时,那么可以被拆分成若干个小的独立的实例(系统变量innodb_buffer_pool_instances设置个数),缓存页的映射是有特定算法的,所以不存在重复缓存页,且在多线程访问时,互不影响。

(TODO Buffer Pool配置注意事项+Buffer Pool的状态信息查看SHOW ENGINE INNODB STATUS

组成

Buffer Pool由n个控制块和n个缓存页还有一些碎片组成,控制块与缓存页一一对应。

  • 缓存页:和磁盘上的页一样都是16kb大小,存放在Buffer Pool后边

  • 控制块:存放了一些控制信息包含页所属的表空间编号/页号/缓存页在Buffer Pool中的位置/链表节点信息/锁信息/LSN信息等,存放在Buffer Pool前边,大小约为缓存页的5%

  • 碎片:Buffer Pool中不能再分配的空间

管理

Buffer Pool在MySQL服务器启动时,就会完成初始化工作:申请Buffer Pool内存空间,划分若干对控制块和缓存页;其中缓存页的的使用情况会用到一些数据格式来管理,如空闲缓存页,被修改过的脏页等用到双向链表。

空闲页

free链表记录Buffer Pool中哪些缓存页是可用的,将缓存页对应的控制块作为一个节点存放在链表中,在Buffer Pool初始化时,是将所有控制块都存放的。free链表定义了一个基节点,存储了链表的头尾节点;每当需要使用一个缓存页时,都会从free链表取出一个空闲的缓存页,将控制信息填上,并将对应的缓存页节点从free链表移除。

缓存页查找

申明一个hash表,以表空间号+页号为key,缓存页为value存储已经被加载到缓存中的缓存页,这样就可以很快定位哪些页已经被缓存了,就无需重复为这个页申请缓存页

脏页

脏页是修改了已经被加载到Buffer Pool中的缓存页数据,导致它和磁盘上的不一致。为了将这些脏页都同步到磁盘上,创建了一个flush链表,用于存储这些脏页的信息,隔一段时间就将这些数据同步到磁盘。flush链表和free链表构造一样

刷新脏页到磁盘,有两种方式(在flush链表的页肯定也在LRU链表)

  • 从LRU链表的冷数据中刷新一部分页面到磁盘BUF_FLUSH_LRU:后台线程定时从LRU链表尾部开始扫描,如果发现脏页就会刷新到磁盘
  • flush链表中刷新一部分页面到磁盘BUF_FLUSH_LIST:后台线程定时从flush链表中刷新一部分页面到磁盘
  • 刷新LRU链表尾部单页到磁盘BUF_FLUSH_SINGLE_PAGE:当用户线程准备加载的一个磁盘页到Buffer Pool,却没有空间,先查找尾部是否有可以直接释放却没有修改的缓存页,如果没有就会强制将LRU链表尾部的一个脏页同步到磁盘

缓存淘汰

Buffer Pool的大小是有限的,所以需要将一些旧的缓存页从Buffer Pool中移除,但是移除缓存页时也期望缓存集中率高

问题

为了考虑两种可能会导致缓存命中率降低情况,所以需要对这个链表做一定的设计

  1. InnoDB提供“预读”的功能,即在执行某个请求后,将它认为之后可能会读到的一些页面预先加载到Buffer Pool中,并存放到LRU链表的头部

预读read ahead

  • 线性预读(使用操作系统核心提供的AIO接口异步读取下一个区中全部的页面到Buffer Pool)
  • 随机预读(如果Buffer Pool中已经缓存了某个区的13个连续(即young区域的头1/4)的页面,不论这些页面是不是顺序读取的,都会触发一次异步读取本区中所有其的页面到Buffer Pool的请求)

这个预读到的页如果真的被访问到,是可以提高效率的,但如果没有被访问,就会浪费内存,且让存放在链表尾部的缓存被淘汰,降低了缓存命中率;

  1. 全表扫描时读取表中所有记录,这时会将该表的所有页都存放到Buffer Pool中,这样可能会让Buffer Pool被完全覆盖,一些命中率非常高的缓存页就被淘汰了,降低了缓存命中率;
实现

LRU链表以按照最近最少使用的原则去淘汰缓存页,将这个链表分为两截(young区和old区,以使用频率高低区分,系统变量innodb_old_blocks_pct确定old区所占比例)

当访问某个页不存在缓存页中时(初始读),将这个缓存页的控制块放到old区,并在对应的控制块中记录下访问时间,这样预读/全表扫描的不被后续访问的页面就会逐渐从old区移除,如果后续被访问时,比较当前访问时间和记录的时间是否在一个时间间隔内(系统变量innodb_old_blocks_time查看),如果不在就会把页放到young区域的头部,反之,不会移动;这样就会减少将young中使用频率较高的页给顶下去的机会。

但是频繁的移动也会产生比较大的开销,所以规定只要被访问的缓存页位于young区域的1/4的后面,才会被移动到LRU链表的头部,降低调整LRU链表的频率

InnoDB缓存---InnoDB Buffer Pool的更多相关文章

  1. Innodb之监控Buffer pool Load progress

    你可以使用PERFORMANCE SCHEMA中的相关信息监控BUFFER POOL状态加载进程. 1. 启用 stage/innodb/buffer pool load instrument: 2. ...

  2. InnoDB Status Output – Buffer Pool and Spin Rounds

    InnoDB has a good source of information about its status which can be requested every time you need ...

  3. 面试题:你有没有搞混查询缓存和Buffer Pool

    一. 关注送书!<Netty实战> 文章公号号首发!连载中!关注微信公号回复:"抽奖" 可参加抽活动 首发地址:点击跳转阅读原文,有更好的阅读体验 使用推荐阅读,有更好 ...

  4. MySQL InnoDB缓冲池(Buffer Pool)

    InnoDB缓冲池并不仅仅缓存索引,它还会缓存行的数据.自适应哈希索引.插入缓冲(Insert Buffer).锁,以及其他内部数据结构. InnoDB还使用缓冲池来帮助延迟写入,这样就能合并多个写入 ...

  5. 在线调整InnoDB Buffer Pool Size

    InnoDB Buffer Pool主要是用来缓存数据表和索引数据的内存区域,它的默认值为134217728字节(128MB).最大值取决于CPU架构;32位系统上的最大值为4294967295(23 ...

  6. 14.6.3.5 Configuring InnoDB Buffer Pool Flushing

    14.6.3.5 Configuring InnoDB Buffer Pool Flushing InnoDB 执行某些任务在后台, 包括脏叶的刷新(那些已经发生改变的pages 但是没有写入到数据文 ...

  7. 一文了解MySQL的Buffer Pool

    摘要:Innodb 存储引擎设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能. 本文分享自华为云社区<MySQL 的 Buffer Pool,终于被我搞懂了>,作者:小林 ...

  8. 关于MySQL buffer pool的预读机制

    预读机制 两种预读算法 1.线性预读 2.随机预读 对预读的监控 一.预读机制 InnoDB在I/O的优化上有个比较重要的特性为预读,预读请求是一个i/o请求,它会异步地在缓冲池中预先回迁多个页面,预 ...

  9. InnoDB存储引擎--Innodb Buffer Pool(缓存池)

    InnoDB存储引擎--Innodb Buffer Pool(缓存池) Innodb Buffer Pool的概念 InnoDB的Buffer Pool主要用于缓存用户表和索引数据的数据页面.它是一块 ...

随机推荐

  1. 基于Groovy编写Ngrinder脚本常用方法

    1.生成随机字符串(import org.apache.commons.lang.RandomStringUtils) 数字:RandomStringUtils.randomNumeric(lengt ...

  2. 根据CPU核心数确定线程池并发线程数(转)

    一.抛出问题 关于如何计算并发线程数,一般分两派,来自两本书,且都是好书,到底哪个是对的?问题追踪后,整理如下: 第一派:<Java Concurrency in Practice>即&l ...

  3. linux-2.6.38 input子系统(用输入子系统实现按键操作)

    一.设备驱动程序 在上一篇随笔中已经分析,linux输入子系统分为设备驱动层.核心层和事件层.要利用linux内核中自带的输入子系统实现一个某个设备的操作,我们一般只需要完成驱动层的程序即可,核心层和 ...

  4. java的概念了解(jdk,jre,jvm,javase,javaee,javame)

    jvm jvm:java virtual machine,俗称:java虚拟机,只认识xxx.class这类文件 jre jre:java runtime environment,俗称java运行环境 ...

  5. CentOS7 解决不能切换中英文输入法的问题

    1. 运行 im-chooser(如果没有要先安装) $ im-chooser 2. 在打开的窗口选择 iBus,然后 Logout 再 Login, 输入法即可切换.

  6. ClassLoader源码分析与实例剖析

    在之前已经对类加载器做了不少实验了,这次主要是来分析一下ClassLoader的源码,当然主要是先从理解官方给它的注释开始,为之后自定义类加载器打好坚石的基础,下面开始: 而从类的层次结构来看也能感受 ...

  7. CSP2019 退役记

    本来想写"退役在即"的,考完 Day2 后直接改成"退役记"了 Day 0 在 ssf 的机房里继续变弱,自己写了一遍 splay 板子,居然写对了,开心 非常 ...

  8. 如何处理请求返回的二进制数据流转化成xlsx文件?

    /* fileName : 文件名 res:二进制流 */ function getOutExcel(fileName, res) { let blob = new Blob([res], { typ ...

  9. golang type conversion

    map[string]interface{} is not the same as map[string]string. Type interface{} is not the same as typ ...

  10. 01windows7下安装rabbitmq

     1.直接双击rabbitmq-server-3.6.10.exe,会提示你缺少Erlang安装包,问你是否下载,点击是就可以了,因为我自己下载,我就直接先安装otp_win64_20.0.exe,直 ...