1.2 InnoDB 核心组件与运行流程
作为 MySQL 默认的存储引擎,InnoDB 是一个复杂的体系。其核心组件大致可以分为“内存”和“后台线程”两大部分,并由 Checkpoint 及 Master Thread 机制统领其运转。
一、 内存组件
InnoDB 是基于磁盘的数据库管理系统,但是磁盘 I/O 速度极慢。为了弥补 CPU 与磁盘之间的速度鸿沟,InnoDB 引入了庞大的内存区域——缓冲池 (Buffer Pool)。
1. 缓冲池 (Buffer Pool)
InnoDB 将数据按 页 (Page) 的方式进行管理,通常一页大小为 16KB。页是磁盘管理的最小单位,也是内存交换的最小单位。与其一条记录一条记录搬运,不如直接搬运 16KB 的整夜进内存。
- 读策略:读数据时,先查缓冲池。如果在,直接走内存;如果不在,去磁盘读取并放入缓冲池。
- 写策略:改数据时,优先修改内存中的缓冲池页(此时该页变为“脏页”),然后在未来的合适时机(通过 Checkpoint 机制)统一写回磁盘。
缓冲池中不仅有数据页,还包括索引页、undo 页、插入缓冲页、锁信息等。
2. 内存链表管理:Free, LRU, Flush
为了高效管理缓冲池的有限空间,InnoDB 用了三个关键链表:
- Free List (空闲链表):记录哪些页是空的。当需要从磁盘读新页时,优先来这里找空位。若没空位,只能去 LRU List 踢人。
- LRU List (冷热链表):记录正在使用的页。普通的 LRU(最近最少使用)算法有致命弱点:一次全表扫描会把真正的热点数据全部踢出内存(缓存污染)。
-
Midpoint 优化:InnoDB 将 LRU 切分为热区(New Sublist)和冷区(Old Sublist,通常占 3/8)。
-
从磁盘新读入的页,首先放在 Midpoint(冷区头部)。如果它在冷区度过了观察期(如 1 秒)且再次被访问,才会晋升到热区头部。这有效防止了全表扫描造成的缓存冲刷。
-
3. Flush List (脏页链表):记录被修改过但还未写入磁盘的页。这些页同时存在于 LRU 中,但由专门的后台线程依据 Flush List 决定何时落盘。
3. Redo Log Buffer 与 额外内存池
- Redo Log Buffer (重做日志缓存):数据在缓冲池被修改时,会同时生成一条 Redo 记录放入这里。
- 额外内存池:用于存放页的控制块信息以及引擎部其他各种数据结构自身所需的内存空间。
二、 后台线程体系
内存里的变化,最终需要人去默默搬运到磁盘上,这就依赖于后台线程。
- Master Thread:核心调度者,负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性。
- IO Thread:InnoDB 大量使用异步 IO (AIO) 处理写请求,多个 IO Thread 负责处理这些请求的回调。
- Purge Thread:事务被提交后,负责顺手回收那些不再需要的 Undo Log 版本,保持系统清洁。
- Page Cleaner Thread:将脏页从 Flush List 刷新到磁盘的任务从 Master Thread 中剥离出来,减轻主线程负担。
三、 Checkpoint 机制
修改的数据虽然在内存里很快,但要是遇到断电,内存数据就没了。Checkpoint 的主要作用就是决定“何时将什么脏页刷回磁盘”。
- 缩短恢复时间:崩溃重启时,只需重放最近一次 Checkpoint 之后的 redo log。而在它之前的所有修改,数据页都已经安稳躺在磁盘里了。
- 内存告急时急救:如 Free List 空了,不得不从 LRU 里踢走脏页,这时必须触发 Checkpoint 进行小规模刷脏。
- 重做日志告急时急救:Redo Log 是循环覆盖写的。如果写满一圈发现旧日志对应的数据还在内存没落盘,就必须马上触发 Checkpoint 刷脏,否则系统将陷入停滞。
注:LSN(Log Sequence Number)是 redo log 的递增序号。当记录 "checkpoint 在 LSN = X" 时,意味着小于等于 X 对应的脏页均已落盘。
四、 Master Thread 工作机制
Master Thread 本质上是一个“大循环调度器”。它通过每秒与每 10 秒的时钟中断,执行不同强度的日常维护逻辑。如果在检测到数据库完全空闲时,还会进入“后台强化清理模式”。
它的核心使命可以概括为维持平衡:
- 合并 Change Buffer:把零散的索引插入合并。
- 刷日志 (Log Buffer 到磁盘)。
- 刷脏页 (基于当前的 I/O 压力和脏页比例)。
- 清理废弃的 Undo 页。