19.InnoDB 的 缓存 Buffer Pool(gold_axe)

https://juejin.im/book/5bffcbc9f265da614b11b731/section/5c238f0851882521eb44c51f

Buffer Pool:
mysql数据库启动的时候, 就向操作系统申请了一片连续的内存, 以后读/写访问以后,把缓存在里面起来, 下次如果命中了就可以省了最昂贵的磁盘IO了
我们设innodb_buffer_pool_size 来控制这块内存的上限

控制块

19.InnoDB 的 缓存 Buffer Pool(gold_axe)_第1张图片
Buffer Pool

每个缓存页,都有对应的一个控制信息, 叫控制块,
控制块从Buffer Pool的前面往后存, 缓存页从后往前存
我们设置的 innodb_buffer_pool_size不包括这些控制块的大小,
操作系统会自动多给一些内存(大概5%)放控制块
剩下放不下一页了就是碎片

控制信息包括该页所属的表空间编号、页号、缓存页在Buffer Pool中的地址、链表节点信息、一些锁信息以及LSN信息(锁和LSN我们之后会具体唠叨,现在可以先忽略),当然还有一些别的控制信息

free链表

19.InnoDB 的 缓存 Buffer Pool(gold_axe)_第2张图片

空闲的页对应的控制块会形成一个双向链表,
刚开始所有的控制块都在这个free链表里面,需要用缓存一页就从free里面得到还空着的缓存页,就把对应的控制块从 free链表移除移除,

19.InnoDB 的 缓存 Buffer Pool(gold_axe)_第3张图片

这个描述链表信息(头/尾/长度)的 就是 基节点
不包括在 Buffer Pool 里面

flush链表

19.InnoDB 的 缓存 Buffer Pool(gold_axe)_第4张图片

和free链表其他都一样, 只是存的是 改写过的页
这些页以后要刷回磁盘的

用来取缓存页的hash表

key: 表空间号+页号
value: 缓存页
这样知道表空间号+页号 就能找到对应缓存页了

LRU链表

Least Recently Used

19.InnoDB 的 缓存 Buffer Pool(gold_axe)_第5张图片

这个链表按比例(可动态设置), 分成2部分 前一部分是 确定常用的页

  • 热数据/young区域: 确定使用频率很高的缓存页,
  • 冷数据/old区域: 使用频率不一定高的缓存页

第一次访问的时候, 先放到冷数据,如果在短时间内又被访问了, 就升级到热数据

这是为了抑制
预读(猜测附近的页/同区也会需要所以都先加载了),

全部扫描
造成的劣币驱逐良币

刷 脏页 到硬盘

后台有专门的线程定时把脏页刷到硬盘

  • LRU 链表的冷数据 尾部
  • flush链表

如果, 需要加载一页到缓存
Buffer Pool 都已经满了,那么

  1. LRU 链表尾部 没有没修改过的, 覆盖掉
  2. 还是不够, 只能把LRU 链表 尾部的脏页先刷, 这样就不是在后台线程做,而是在用户线程做, 严重降低处理速度了

把 Buffer Pool 拆成多个

多线程环境下, 没有线程要访问 Buffer Pool 都要改控制块连成的链表, 只能都加锁,并发很高的情况下 会影响请求速度
可以把它们拆分成若干个小的Buffer Pool,每个Buffer Pool都称为一个实例,它们都是独立的


19.InnoDB 的 缓存 Buffer Pool(gold_axe)_第6张图片

实例们平分Buffer Pool 设置的大小

5.7.5 以后 为了运行调整 Buffer Pool 大小的改进

19.InnoDB 的 缓存 Buffer Pool(gold_axe)_第7张图片

在Buffer Pool 实例内部 以 chunk为单位来使用缓存, 一个 chunk才是连续的内存, chunk 之间不连续

每个chunk 多大, 运行前配置好, 启动以后不能改了

你可能感兴趣的:(19.InnoDB 的 缓存 Buffer Pool(gold_axe))