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. QT调用CHM方法

    QDesktopServices desktopServices;QString strUrl=QCoreApplication::applicationDirPath () ;strUrl=QStr ...

  2. JDialog

    JDialog继承Dialog,Dialog继承Window,所以可以用setLocationRelativeTo(Component c)来实现Dialog的显示,当c为空时,直接显示在屏幕前,为组 ...

  3. Javascript简单教程汇总

    什么是函数 一段定义好的代码,并可以反复使用的代码块 函数的作用 提升代码的可复用性,将一段代码进行预定义,需要使用的时候才触发 代码块 形成了一个相对独立的作用域 语法: function  函数名 ...

  4. 利用浏览器做好数字进制和ASCII码及Unicode教与学

    浏览器是现在个人计算机的标配,一般来说一个PC至少安装一种以上的浏览器.主流网页浏览器有Google Chrome.Internet Explorer.Microsoft Edge.Mozilla F ...

  5. .NET 使用事物调用存储过程

    using System; using System.Collections.Generic; using System.Configuration; using System.Data; using ...

  6. 【Distributed】分布式Session一致性问题

    一.概述 1.1 什么是Session 1.2 Session实现原理 1.3 Session常见问题 Session 保证在那里? 关闭浏览器Session会失效吗 服务器集群之后,Session产 ...

  7. shell数组处理

    linux shell在编程方面比windows 批处理强大太多,无论是在循环.运算.已经数据类型方面都是不能比较的. 下面是个人在使用时候,对它在数组方面一些操作进行的总结.   1.数组定义   ...

  8. java 使用POI导出百万级数据

    先看结果吧,这只是测试其中有很多因数影响了性能. 表总数为:7千多万,测试导出100万 表字段有17个字段 最终excel大小有60多兆 总耗时:126165毫秒 差不多2分多钟 其核心简单来说就是分 ...

  9. CF700E Cool Slogans——SAM+线段树合并

    RemoteJudge 又是一道用线段树合并来维护\(endpos\)的题,还有一道见我的博客CF666E 思路 先把\(SAM\)建出来 如果两个相邻的串\(s_i\)和\(s_{i+1}\)要满足 ...

  10. poj3694 Network[边双缩点+树剖/并查集]

    首先同一个点双内部的加边肯定不影响..所以先缩点成树,然后每次加一条边,这条对应的树上路径上所有边就都不是桥了,且每次操作独立作用,不相互影响(不过有可能本来一条边已经不是桥了又被标记了一次),所以每 ...