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. 【转】Fetch超时设置和终止请求

    原文链接:https://www.cnblogs.com/yfrs/p/fetch.html 1.基本使用 Fetch 是一个新的端获取资源的接口,用于替换笨重繁琐XMLHttpRequest.它有了 ...

  2. localStorage、sessionStorage和cookie的区别

    本地客户端(浏览器)查看三者信息: HTML4的本地存储:cookie 浏览器的缓存机制提供了可以将用户数据存储在客户端上的方式,可以利用cookie,session等根服务端进行数据交互. 一.co ...

  3. JavaSpring【七、AspectJ】

    AspectJ 概念 @AspectJ类似纯Java注解的普通Java类 Spring可以使用AspectJ来作为切入点 AOP在运行时仍是纯SpringAOP,对AspectJ无依赖 配置: 对@A ...

  4. 【1】Git基础

    一.Git概念 1.1.Git定义   Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发 ...

  5. 制作docker 离线仓库

    目录 制作docker 离线仓库 1.前言 2.步骤 安装docker-distribution 编辑docker-distribution服务的配置,使用yaml进行的配置 启动仓库服务 编辑doc ...

  6. Delphi 定义线程对象

  7. vsftpd的安装和配置

    1  安装vsftpd sudo apt-get install vsftpd 2  测试是否安装成功 sudo service vsftpd restart 如果有反应即成功 3  彻底卸载vsft ...

  8. BCB 如何拦截TAB键消息

    最近项目中一个需求,按下Tab键,按照指定的顺序进行跳转. 在实现的过程中发现,Tab按下的时候,会让当前控件失去焦点.并跳转到其他可焦点控件 例如 TEdit,TButton 等. 究其原理,是因为 ...

  9. JavaScript实现数据的双向绑定

    接触到Angulr.js和Vue.js后,提到最多的就是双向绑定 下面将用JavaScript实现数据的双向绑定 <!DOCTYPE html> <html> <head ...

  10. TypeError: Cannot read property '$$' of undefined at HTMLElement._attached.wx.getPlatform._touchstartHandlerForDevtools

    TypeError: Cannot read property '$$' of undefined     at HTMLElement._attached.wx.getPlatform._touch ...