innoDB
分为内存结构和磁盘结构两个部分,其中内存结构的主要部分是buffer pool。
buffer pool
innoDB的内存架构的主要部分
本质与作用
buffer pool是innoDB引擎内的一个重要组件,是一个内存缓存,它的性能直接影响到innoDB的表现。通过缓存数据和索引,将磁盘 I/O 转化为内存操作,使 CRUD 操作从 毫秒级(磁盘) 降至 微秒级(内存)。合理配置 Buffer Pool 大小、实例数和刷盘策略,是优化 MySQL 性能的关键步骤。
作用:缓存磁盘上的表数据页(data page
)和索引页(index page
),减少磁盘 I/O。
读的大概流程:查询到某个buffer pool实例,使用哈希算法找到要查取的数据,查取,然后返回,如果没查到,去磁盘查,读到buffer pool中。 写的大概流程:先把数据和日志写入 buffer pool 和 log buffer,再由后台线程以一定频率将 buffer 中的内容刷到磁盘,「这个刷盘机制叫做Checkpoint」。
大致的查询流程如下:[1]
内部结构
Buffer Pool的本质就是一大块内存数据结构,由多个缓存页和其控制块组成,另外配套的各种链表数据结构(free、flush、LRU)来辅助执行引擎的运行。
结构:
Buffer Pool 通过 数据页(缓存页) + 控制块 的组合存储数据,利用 Free/LRU/Flush 链表 管理页的生命周期,结合 哈希表 加速访问,并通过 多实例与 Chunk 优化高并发场景。其设计核心是平衡内存利用率、访问效率和数据一致性,是 InnoDB 实现高性能的关键。
存储数据
由 缓存页+控制块 构成,数据存在缓存页中,控制块存这个缓存页的元信息[2]。 在Buffer Pool中,每个缓存页的控制块放在最前面,然后各个缓存页放在后面,大概如下图所示:[3],[4]
Buffer Pool默认大小 128M,用于缓存数据页(16KB),控制块大小约800个字节(不到1KB)。所以配置 innodb_buffer_pool_size=128M 时,InnoDB 实际会申请约 134MB 内存(多出的 6MB 用于控制块)。
free链表
当需要加载新的缓存页时,执行引擎是如何知道哪些缓存页是空闲的呢?
答案是使用free链表对空白缓存页进行管理,在Buffer Pool中会有一个双向链表数据结构的free链表。在这个链表中存储的每个节点是一个空闲缓存页的控制块的地址。只要存在一个缓存页是空闲的,此时对应的控制块就会被放入这个free链表中。
flush链表
如果一个缓存页被写了,那么这页就成为脏页,flush链表就是记录脏页的。其原理和free链表一样,只不过存的是脏页而不是空白页。
LRU链表
成熟的缓存都有这个机制,不然只进数据不出数据,是不现实的。 这里的lru链表和其他的lru链表也没什么不同,都是只要被查取了,就放到前面去,淘汰就拿最后的。
冷热分离策略
MySQL会预读多一些的数据,多出来的数据,不能算是热点数据,如果放到链表前面,把后面的真热点数据挤出去了,是很不好的事情。这里lru会采用冷热分离的策略,大致思路就是把真热点数据放到前面,预读来的非热点的数据放到后面。冷热数据的比例是由参数innodb_old_blocks_pct参数控制的,默认配置为37,代表了冷数据占比37%
简答:
将 LRU 链表分为两部分:
new 区(热数据区):占 63%
old 区(冷数据区):占 37%
新数据从 midpoint(冷数据区头部)插入
数据页在 old 区停留时间超过
innodb_old_blocks_time
(默认 1s)后,再次访问才会移到 new 区19
哈希表
MySQL如何知道一个数据页是否被缓存?答案是使用哈希表。 这个哈希表的key采用表空间号和数据页号组成,value存储缓存页地址。
脏页-刷盘持久化
通过对上述三种链表的描述,我们知道「当我们对数据进行修改时,其实修改的是Buffer Pool 中数据所在缓存页,修改后将其设置为脏页,并将脏页的控制块同时存在于 LRU 链表和 Flush 链表」。然后通过刷脏将修改同步至磁盘[5]。
刷脏不是每次修改都进行的,那样性能会很差,因此刷脏是通过一定的时机触发进行批量刷盘的。
脏页的刷盘时机总的来说就分为以下种:
redo log 日志满了的情况下,会主动触发脏页刷新到磁盘;
MySQL 正常关闭之前,会把所有的脏页刷入到磁盘;
Buffer Pool 空间不足时,会淘汰一部分数据页,如果淘汰的是脏页,需要先将其同步到磁盘。
MySQL 空闲时,后台线程会定期脏页刷盘
--
注释&引用
[1]MySQL缓冲池(buffer pool),这次终于懂了_mysql bufferpool-CSDN博客
[2]缓存页原信息指的是当前缓存页所对应的表空间、数据页编号、当前缓存页在Buffer Pool中的地址信息等。
[3]所有相似风格的图中所有《描述数据》都为文中的《控制块》
[4]04.MySQL InnoDB Buffer Pool深度解析 - 《MySQL》 - 极客文档
[5]MySQL十六:36张图理解Buffer Pool - 云扬四海 - 博客园