InnoDB 的 Buffer Pool

对于使用InnoDB存储引擎来说,无论是存储用户数据的索引,还是各种系统数据,最终都是以文件的形式存放于磁盘中,InnoDB存储引擎 在处理客户端的请求时,如果需要访问某个页的数据,就会把完整的页中的全部数据加载在内存中,而且在读写访问之后,并不着急把该页的内存释放掉,而是将其缓存起来,这样将来有请求访问该页时,就可以省下磁盘IO的开销。

Buffer Pool

为了缓存磁盘中的页,MySQL 启动时就会向OS申请一大块连续的内存,这就是 Buffer Pool。该值也可以在配置文件中配置:

最小值为5MB,小于5MB会自动配置为5MB。

Buffer pool 对应的连续内存被划分为若干个页面,页面大小于InnoDB 表空间使用的页面大小一致,默认都是16KB,我们将其称为缓冲页。为了管理这些缓冲页,InnoDB 为每一个缓冲页都创建了一些控制信息,包括:表空间编号,页号,缓冲页在 Buffer Pool 中的地址,链表节点信息等。

这些缓冲页对应的控制信息占用的内存大小都是相同的,我们把每个页对应的控制信息占用的一块内存称为一个控制块。控制块和缓冲页都存放到 Buffer Pool 中,控制块存放到 Buffer Pool 前面,缓冲页存放到 Buffer Pool 的后面,所以整个 Buffer Pool 对应的内存空间看起来如图所示:

free 链表的管理

最初启动MySQL,完成 Buffer pool 初始化之后,现在并没有磁盘页被缓存到 Buffer Pool 中,那么当从磁盘读取到第一页到 Buffer poo 中时,该存放到Buffer Pool 中的哪一个缓冲叶呢?或者说怎么区分缓冲页哪些是被使用了,哪些是没有被使用呢?

MySQL 是这样做的,把所有空闲缓冲页的控制块作为一个链表节点,依次串起来,我们将这个链表称为 free 链表。

  • 缓冲页的hash处理
    当我们需要访问某个页中的数据时,就会把该页从磁盘加载到 Buffer Pool 中,但是如果该页已经在 Buffer Pool 中,那么直接使用就可以了。那么问题来了,我们怎么知道该页在不在 Buffer Pool 中呢?
    我们其实是用 表空间号 + 页号 来定位一个页的。也就相当于 key = 表空间号 + 页号,value=缓冲页的控制块。怎么通过一个key来快速找到一个value呢?当然是哈希表了。

    所以在需要访问某个页的数据时,先从哈希表中根据表空间号+页号看看是否有对应的缓冲页,如果有,直接使用该缓冲页就好,如果没有,就从free链表中选择一个空闲的缓冲页,然后把磁盘中对应的页加载到该缓冲页的位置。

flush 链表的管理

如果我们修改了 Buffer Pool 中的某个缓冲页的数据,它就与磁盘上的页不一致了,这样的缓冲页称为脏页。当然我们可以每当修改完某个缓冲页时,就立即将其刷新到磁盘对应的页上,但是频繁的往磁盘写数据会严重影响磁盘性能。所以,并不着急将修改刷新到磁盘上,而是在未来的某个时间节点上。

为了管理这些脏页,如同 free 链表类似的思路,建立一个存储脏页的链表,凡是被修改过的缓冲页对应的控制块都会作为一个节点加入到这个链表中,这个链表称为flush链表。

LRU 链表的管理

Buffer Pool 对应的内存大小总是有限的,当 free 链表已经没有多余空闲缓冲页时,就需要把旧的缓冲页从 Buffer Pool 中移除,然后再把新的页放进去,那么,就有个问题产生了,移除哪些缓冲页呢?

简单的LRU链表
MySQL 这里采用的时LRU算法(按照最近最少使用的原则去淘汰缓冲页),按照同样的方法再创建一个链表,当需要访问某个页时,按照下面的方法来处理:

  • 如果该页不在中,在把该页从磁盘加载到 Buffer Pool 中的缓冲页时,就把该缓冲页对应的控制块作为节点塞到LRU链表头部。
  • 如果该页已经被加载到 Buffer Pool 中,则直接把该页对应的缓冲控制块移动到LRU链表头部。

也就是说,只要我们使用到了某个缓冲页,就把该缓冲页调整到 LRU 链表头部,这样,LRU链表尾部就是最近最少使用的缓冲页了,所以,当 Buffer Pool 中的空闲链表使用完时,直接到LRU链表的尾部找些缓冲页淘汰掉就行了。

  • 划分区域的 LRU 链表
    上面的这个简单的 LRU 链表用了没多长时间就发现问题了。它不能对付下面2种情况:
    1. 情况一:InnoDB 提供了一个看起来比较贴心的服务 -- 预读。前边说过:只有当我们用到某个页时,才会将其从磁盘加载到 Buffer Pool 中,用不到则不加载。而预读就是:当InnoDB 执行当前请求时,可能会在后面读取到某些页面,就预先把这些页面加载到 Buffer Pool 中。按照触发方式不同,预读又分为:

      • 线性预读
      • 随机预读

      预读

    2. 全表扫描

上面2种问题,总结出来:

  • 加载到 Buffer Pool 中的页不一定用得到
  • 如果有非常多的使用频率偏低的页被同时加载到 Buffer Pool 中,则可能会把哪些使用频率非常高的页从 Buffer Pool 中淘汰掉

刷新脏页到磁盘

后台有专门的线程负责每隔一段时间就把脏页刷新到磁盘,这样就可以不用影响用户线程处理正常的请求。刷新的方式主要有2种:

  • 从LRU链表的冷数据种刷新到一部分页面到磁盘

  • 从flush链表的冷数据刷新一部分页面到磁盘

查看Buffer Pool 状态信息

MySQL 提供了 `` 语句来查看InnoDB存储引擎运行过程中的一些信息,其中就包括 Buffer Pool 的信息。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容