⑤ Buffer Pool:定位、结构与三大链表

对应第 11 ~ 15 讲 · 缓存页与描述数据 · free / flush / LRU · 缓存命中率

Buffer Pool 的定位与结构(11 ~ 12 讲) 三大链表(13 ~ 14 讲) 缓存淘汰的起点:缓存命中率与 LRU(15 讲) 结构清楚后,看运行机制 三大链表联动 为什么需要 Buffer Pool? 直接随机读写磁盘太慢(几百毫秒级)· 每秒只能扛几百请求 增删改先操作内存缓存 · redo log 保证崩溃后可恢复 默认 128MB · 生产要调大 16核32G 机器建议 2GB:innodb_buffer_pool_size=2147483648 数据页与缓存页 16KB 一一对应 行数据存在数据页里 · 更新一行 = 加载整页进缓存 描述数据 ~800B(约 5%):表空间号 + 页号 + 内存地址 内存碎片与布局 划分后剩余零头放不下缓存页就是碎片 · 缓存页与描述块紧密排列可减少 free 链表 · 空闲缓存页 空闲页的描述块串成双向链表(free_pre / free_next) 基础节点 40B:头/尾地址 + 空闲数量 加载数据页四步 free 取描述块 → 读磁盘页入缓存页 → 写描述数据 → 从 free 链表移除 数据页缓存哈希表 key = 表空间号+数据页号 → value = 缓存页地址(防重复加载) flush 链表 · 脏页记录 被修改过的缓存页(与磁盘不一致)描述块串成双向链表 记录哪些页后续要刷回磁盘 缓存页满了怎么办? free 链表空了 → 必须淘汰缓存页腾位置 淘汰 = 脏页刷盘 + 清空 + 加载新数据页 缓存命中率 100 次请求 30 次命中缓存 → 高命中 · 不用走磁盘 刚加载只用 1 次的页 → 占着位置没产出,优先淘汰它 LRU 链表(Least Recently Used) 加载 / 访问 → 移到链表头部 淘汰时取尾部 = 最近最少使用的缓存页 表/行 = 逻辑概念 · 表空间/数据页 = 物理概念 但是!简单 LRU 漏洞百出 预读 + 全表扫描会把没人访问的页堆到链表头部 热数据反而被挤到尾部 淘汰时误杀热数据 → 解决方案见下一篇 图例 核心结构 链表机制 参数 / 数值 问题警示 概念引入

Buffer Pool 结构速记

  • • 默认 128MB,生产按机器内存调大(如 2GB)
  • • 磁盘数据页 = 16KB,缓存页一一对应
  • • 描述数据 ~800B/页(约 5%),放在最前面
  • • 实际占用比设定值略大(128MB → 130 多 MB)

三大链表 + 一个哈希表

  • • free:哪些缓存页空闲可用
  • • flush:哪些缓存页是脏页待刷盘
  • • LRU:哪些热哪些冷,淘汰谁
  • • 哈希表:表空间号+页号 → 是否已缓存
  • • 链表节点就是描述数据块(指针复用,不复制)

淘汰缓存页的决策逻辑

  • • 目标:缓存命中率最大化
  • • 淘汰"占着位置没产出"的冷页
  • • LRU:头部最热、尾部最冷
  • • 但简单 LRU 会被预读和全表扫描击穿