第 2 篇 把操作收进 Session / Cursor;真正占内存配额、决定能否继续写的,是 Cache。Architecture Guide Cache 开篇三句已经给出本篇坐标系:
- Cache 保存最近访问或修改的数据副本;B-Tree 页按需读入。
- 空间不足时由 Eviction 移出不需要的页。
- 更新改的是 cache 中的页,经 Checkpoint 或 Eviction 异步刷到存储。
本文钉住:WT_CACHE / WT_REF /
WT_PAGE 结构、clean 与 dirty
计量、页内修改如何挂链——不展开 eviction 线程调度(第 4
篇)与 reconcile 写镜像(第 6 篇)。
本文是「WiredTiger 内核」系列第 3 篇(共 17 篇)。→ 系列目录
先修:第 1–2 篇。续读:第 4 篇 Eviction;第 5 篇 update chain。
版本锚定:Architecture Guide Version 12.0.0 /
developCache;源码mongodb-8.0的src/include/btmem.h、cache.h、src/cache/。Guide 声明不与发版锁步。
一、为什么有两套页布局
Guide 写明:cache 中的页布局为多线程并发访问优化;磁盘上的页布局为节省存储优化。因此读页、写页都要在 in-memory 与 on-storage 表示之间转换——写路径上的转换就是 reconciliation(第 6 篇)。
这与 PostgreSQL shared buffers「页在池中大体保持磁盘页格式再加少量元数据」的直觉不同:WT 明确把「内存形态」和「磁盘镜像」拆开。代价是 dirty 页不能「直接丢掉」或「原样 DMA 出去」,必须先收成 on-disk image。
二、WT_CACHE、WT_REF、WT_PAGE
2.1 全局 cache
- 每个 connection 一个
WT_CACHE,经WT_CONNECTION_IMPL访问。 - 内含用量计数、eviction 相关参数,以及 eviction 进度状态(Cache · Cache structure)。
- 配置项
cache_size默认 100 MB;MongoDB 默认把 cache 设为物理内存的一半(Guide 原文注记)。内存来自 C 堆分配器:驱逐只把内存还回 allocator,不保证进程 RSS 立刻下降。
2.2 按需读页
打开文件时加载 B-Tree 根页以及第一层 internal 页。查找从根下行;遇到不在内存的页,把 address cookie 交给 Block Manager,取回块,必要时解密/解压,再分配索引结构以支持键的二分查找。
flowchart LR
root["Root WT_REF"] --> intl["Internal WT_PAGE"]
intl --> ref2["Child WT_REF"]
ref2 -->|"not in cache"| load["Block Manager read"]
load --> leaf["Leaf WT_PAGE"]
ref2 -->|"in cache"| leaf
2.3 WT_REF 与 WT_PAGE
| 结构 | 角色 |
|---|---|
WT_REF |
指向「cache 中的页」或「尚未加载的页」;B-Tree 打开时根
WT_REF 挂在 WT_BTREE 上 |
WT_PAGE |
已加载页:含解压后的 on-disk image 缓冲,以及访问/更新用的附属结构 |
| Internal 页 | 子页数组为 WT_REF |
| Row-store leaf | WT_ROW 数组(页上 KV);支持二分查找 |
| VL column leaf | WT_COL + WT_COL_RLE |
几乎所有在这些结构上的操作设计为 lock-free,以支撑高并发 cache 访问(Guide)。
2.4 什么计入 cache_size
计入:B-Tree 数据及相关内存结构(索引、insert list、update chain)。
不计入:dhandle、cursor、session;以及读写磁盘镜像时临时分配、转换用完即释放的缓冲区。
运维含义:cacheSizeGB
不是进程内存上限;连接数、cursor 泄漏仍可推高 RSS(第 15
篇)。
三、clean / dirty 与第一次修改
Guide 定义:
- Clean:cache 中与磁盘版本相同的数据。
- Dirty:已修改、需要与磁盘 reconcile 的数据。
用量上同时跟踪总量、clean、dirty。总量过高或 dirty 过多时触发 Eviction(第 4 篇)。
驱逐差异(本篇只记结论):
| 页状态 | 离开 cache 前要做什么 |
|---|---|
| Clean | 直接释放内存;磁盘副本不变 |
| Dirty | 先 reconcile(转 on-disk 格式)再写存储,然后才能释放 |
3.1 WT_PAGE_MODIFY
叶页上某条目首次插入或修改时,为该
WT_PAGE 分配 WT_PAGE_MODIFY。
Row-store leaf:
- 每个页上 KV 对应一个
WT_UPDATE*;多次更新串成链表(update chain)。 - 删除用特殊 tombstone 更新表示。
- 新键插入走
WT_INSERTskiplist:页内相邻键之间的间隙(以及页首/页尾间隙)各有一条 skiplist。
Column-store leaf:用一对 skiplist 分别跟踪 append 与 update(本系列默认 MongoDB row-store 路径,列存仅作对照)。
flowchart TB
page["WT_PAGE leaf"] --> mod["WT_PAGE_MODIFY"]
mod --> upd["WT_UPDATE chains<br/>per on-page key"]
mod --> ins["WT_INSERT skiplists<br/>gaps between keys"]
未提交更新挂在链上、不进磁盘镜像——与第 08 篇「提交后才进入可持久化历史」一致;把链收成磁盘最新值 + HS 旧值的步骤是 reconciliation。
四、Shared cache(边界)
Guide 描述:同一进程多个数据库 connection 时可启用
shared cache,由 cache pool server 按
pressure(miss 与 eviction 等待的加权)在 connection
间动态划分配额。MongoDB 单实例单 dbPath
的常见部署不依赖该模式;本系列正文默认单
connection 固定
cache_size。需要多租户同进程时再回查 Shared
caches 节。
五、与 PG 缓冲池对照(机制,非排名)
| 维度 | PostgreSQL Buffer Pool(站内口径) | WiredTiger Cache |
|---|---|---|
| 页格式 | 大体保持磁盘页 + 描述符 | 内存布局与磁盘布局分离 |
| 脏页写出 | 检查点 / 后台写等 | Eviction 或 Checkpoint 路径上 reconcile |
| 版本 | 堆元组 / 提示位等 | update chain + 事后 HS |
| 计量 | shared_buffers 等 | clean/dirty/updates 分触发(第 4 篇) |
对照目的:读过 PG 的人不要假设「pin 住 buffer 再改字节」等于 WT 的修改模型。深度对照见第 16 篇。
六、争论、间隙与开放问题
谱系(短): 页式缓存是数据库经典组件;WT 的分叉点是 in-memory 页 + update chain 与 on-disk image 显式分离,并与 Durable History 联动(第 08 篇)。
工程间隙: Guide 中的默认
cache_size 与 MongoDB 默认「一半
RAM」不同——排障时以 MongoDB 实际配置为准。本篇无本地
db.serverStatus() 实测。
开放问题: HS
页与用户热页是否公平争用同一 WT_CACHE——第 4、15
篇给机制入口;可复现阈值需实测,本篇不下性能结论。
七、收束
- Cache 按需加载 B-Tree 页;
WT_REF表示「在或不在内存」,WT_PAGE是已加载形态。 - 计量分 clean / dirty;dirty 不能直接扔,必须 reconcile。
- 修改挂在
WT_UPDATE/WT_INSERT上;session/cursor 不计cache_size。
下一篇:Eviction——谁在什么阈值下把页赶出 cache,以及 dirty eviction 如何强制走 reconcile 与 History Store。
参考资料
规范 / 官方文档
- WiredTiger Architecture Guide, Cache:https://source.wiredtiger.com/develop/arch-cache.html
- WiredTiger Architecture Guide, Eviction(clean/dirty 定义与驱逐后果)
- WiredTiger Architecture Guide,
B-Trees(
WT_REF/ 页关系)
源码
mongodb-8.0:src/include/btmem.h、cache.h、cache_inline.h;src/cache/cache.c、cache_pool.c
站内
上一篇:Connection
/ Session / Cursor
下一篇:Eviction
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【WiredTiger 内核】Eviction:脏页必须先 reconcile
拆解 WiredTiger Eviction 的 server/worker/队列、target/trigger 阈值,以及 dirty eviction 经 reconciliation 把最新值写入用户表、旧版本写入 History Store;说明应用线程被迫协助驱逐的条件。
【WiredTiger 内核】文档库存储引擎全景:MongoDB 默认引擎的生态位
定位文档库默认引擎 WiredTiger 相对 PG/InnoDB/SQLite/RocksDB 的生态位;钉住 Session→Cache→Reconcile→HS→Checkpoint 主线、站内分工与 17 篇阅读路线,并以 Berenson 隔离词汇与 Durable History 为学术/工程锚点。
【WiredTiger 内核】运维与排障:HS 膨胀、cache 压力与长游标
给出 WiredTigerHS.wt 膨胀、cache dirty/eviction 压力、长游标与备份窗口的可复现排查口径;强调禁止手工删除 HS/日志文件,并把现象映射回本系列机制篇。
【WiredTiger 内核】Cache · Eviction · Reconciliation · History Store · Checkpoint
补齐文档库默认引擎内核层:从 Connection/Session、Cache/Eviction、B-Tree update chain、Reconciliation 到 Timestamps、History Store、Checkpoint/Journal 与 Rollback-to-Stable,并以 MongoDB 嵌入边界与 PG/InnoDB/RocksDB 对照收束。