P24 Mysql 引擎层 BufferPool 工作过程原理
面试题:InnoDB 的 Buffer Pool 是什么?一次查询/更新在 Buffer Pool 里是怎么工作的?
1. Buffer Pool 是什么
InnoDB 在内存里维护的一块缓存区域(默认 128MB,通常配置为物理内存的 60%~70%),缓存数据页(16KB)和索引页,避免每次读写都走磁盘。
text
读:先看 Buffer Pool,命中直接返回;未命中再从磁盘加载进 Buffer Pool
写:先改 Buffer Pool 里的页(脏页),后台异步刷盘2. 读数据的过程
text
SQL → 定位索引页 → 检查 Buffer Pool 是否有该页
├─ 命中:直接读内存页返回
└─ 未命中:从磁盘读页 → 放入 Buffer Pool(按 LRU 淘汰)→ 返回3. 写数据的过程(关键:先改内存,异步刷盘)
text
UPDATE 某行
→ 行所在数据页在 Buffer Pool 中(不在则先加载)
→ 修改内存中的页(变成脏页)
→ 写 redo log(记录"改了什么",保证崩溃可恢复)
→ 事务提交
→ 后台线程(Master/刷盘线程)在适当时机把脏页刷回磁盘这就是WAL(Write-Ahead Logging):先写日志、后刷数据页,保证性能和数据安全。
4. 页面淘汰:LRU 与改良
InnoDB 用 LRU(最近最少使用) 管理页,并做了改良:
- 链表分成**新生代(young)和旧生代(old)**两段;
- 新读入的页先进 old 区,被再次访问才晋升 young 区;
- 防止"一次大范围扫描"把热数据全部挤出内存(缓冲池污染)。
配置:innodb_buffer_pool_size、innodb_old_blocks_time。
5. 相关概念
- 脏页:内存中被修改、还没刷盘的页;
- Free List / LRU List / Flush List:空闲页链表、LRU 链表、待刷盘脏页链表;
- Change Buffer(写缓冲):对非唯一二级索引的插入/更新先缓冲,减少随机 IO;
- doublewrite buffer:刷盘前先写双写缓冲,防止页半写损坏。
加分点
- 为什么 Buffer Pool 要大:命中率越高,磁盘 IO 越少;
show engine innodb status可看命中率; - 多个 Buffer Pool 实例(
innodb_buffer_pool_instances)减少并发锁竞争; - 追问"重启后缓存丢失怎么办":冷启动后命中率低,可用预热(如
SELECT ...扫描热点页)。
一句话总结
Buffer Pool 是 InnoDB 的内存页缓存:读命中内存、未命中才读磁盘;写则先改内存页并记 redo log(WAL),后台异步刷盘;用改良 LRU 淘汰页,配合 Change Buffer、doublewrite 等机制兼顾性能与安全。