土法炼钢兴趣小组的算法知识备份

【WiredTiger 内核】Eviction:脏页必须先 reconcile

文章导航

分类入口
databasestorage
标签入口
#wiredtiger#eviction#dirty-page#reconciliation#history-store#cache#lru#mongodb

目录

第 3 篇 说明 Cache 按 clean/dirty 计量,且 dirty 页不能直接释放。把页真正赶出 cache 的子系统是 Eviction。Architecture Guide Eviction 把目标说死:把 cache 维持在用户设定的总量与 dirty 上限内;一旦超过 target,就触发驱逐把用量压回去。

本文钉住:线程与队列结构、clean vs dirty eviction、target/trigger 旋钮、以及「应用线程被迫做驱逐」的条件。Reconciliation 与 HS 写入的细节分别在第 6、8 篇;本篇只钉 契约:dirty eviction ⇒ reconcile ⇒ 最新进用户表、旧版进 History Store。

本文是「WiredTiger 内核」系列第 4 篇(共 17 篇)。→ 系列目录

先修:第 3 篇。续读:第 5–6 篇(update chain / Reconciliation);第 08 篇 History Store

版本锚定:Architecture Guide Version 12.0.0 / develop Eviction;源码 mongodb-8.0src/evict/。结构名以 Guide 表为准(WT_EVICT、队列条目等);Guide 不与发版锁步。


一、目标与组件

Eviction 由以下部分组成(Eviction):

组件 职责
Eviction server(1) 遍历各树,找可驱逐候选;近似 LRU 排序后把较旧的一批推进队列
Worker threads(0…N) 从队列取页并执行驱逐;数量可在配置的 min/max 间动态伸缩
Queues(3) 两条普通队列 + 一条 urgent 队列

Server 在树与树之间尽量公平,并记住每棵树上次走到的位置。候选按最近访问时间排序后,取大约 三分之一最旧 的可驱逐页入队——Guide 称之为近似 LRU。

Worker 通过条件变量与 server 协作:等队列有活,再独立驱逐直到队列空。也可以配置为只有 server、没有 worker:此时 server 自己找页并驱逐。

flowchart LR
  srv["Eviction server<br/>walk trees approx LRU"] --> q["Ordinary queues"]
  srv --> uq["Urgent queue"]
  q --> wk["Worker threads"]
  uq --> wk
  wk --> clean["Clean: free memory"]
  wk --> dirty["Dirty: reconcile then write"]
  app["App thread under pressure"] --> dirty

二、Clean vs dirty eviction

Guide 定义与第 3 篇一致,驱逐路径分叉:

类型 条件 行为
Clean eviction 页无脏内容 直接从内存移除;磁盘页不变
Dirty eviction 页已修改 走 reconciliation:丢掉过时内容;最新值进 data store(用户表)更旧值进 History Store

这是本系列主线最硬的一句工程契约,也是 第 08 篇 「用户表只留最新、旧版旁路」在 eviction 路径上的落点。Checkpoint 路径同样 reconcile 脏页,但动机是持久化一致快照(第 9 篇);Eviction 的动机是 腾 cache

独占与读者

若仍有线程在读该页内容,页不能被驱逐;server/worker 在确认可驱逐后必须锁定并取得排他访问,避免检查通过后并行读者再进入。

Urgent 队列

强制驱逐标记的页进入 urgent 队列(在下列条件满足时;否则可由应用线程自行驱逐该页):

Urgent 队列优先于普通队列。


三、Target 与 Trigger

可在 wiredtiger_openWT_CONNECTION::reconfigure 配置。对每一对指标:target 必须低于对应 trigger

配置项 含义(Guide)
eviction_target 总体 cache 用量目标(占 cache 百分比);达到后 worker 积极驱逐
eviction_trigger 总体用量触发线;达到后应用线程开始参与驱逐
eviction_dirty_target / eviction_dirty_trigger 同上,但只针对 dirty 占比;dirty 达 dirty_trigger 时应用线程会被节流并做驱逐
eviction_updates_target / eviction_updates_trigger 针对 cache 中 updates 字节量;达 trigger 时应用线程参与

「任何自读入磁盘后被修改过的页」都算 dirty。

应用线程协助驱逐

当工作负载写入速度超过 eviction 清理速度、cache 压不下来时,应用线程在继续读/写之前会被要求先完成部分 worker 同类工作。这是正确性/稳定性机制,不是可选优化——表现为延迟尖刺时,应同时看 dirty 比例与 eviction 统计(第 15 篇),而不是只加 cacheSizeGB

MongoDB 把部分旋钮映射到存储引擎参数;具体名以手册为准,机制以本表为准。


四、与 Checkpoint 的衔接(预告)

Checkpoint 章:在 checkpoint 事务开始(pin 住内容)之前,会先借 eviction 把 dirty 压到目标比例,以利用多线程 eviction、缩短 checkpoint 临界区;checkpoint 线程会等待,除非看不到进展。

含义:eviction 不只是「内存满了才跑」的后台 GC,也是 checkpoint 的前置减压阀。第 9 篇展开顺序:锁 → eviction 减压 → prepare → 用户表 → HS → flush → 元数据。


五、HS eviction 与用户表 eviction

Guide Eviction 在 dirty 路径上写明旧版本进 History Store;History Store 自身的页也会占用同一 cache,并参与驱逐。第 08 篇开放问题 3 问的正是:历史页与用户热页抢同一池时,主路径是否可变慢。本篇只钉机制入口:

没有本站实测前,不写「HS 占比 X% 即异常」之类阈值。


六、争论、间隙与开放问题

争论(有 Guide 依据): 应用线程参与 eviction 保证 cache 有界,但把延迟尖刺推到前台请求。调高 cache 或放宽 dirty_trigger 只是推迟矛盾,不取消「脏页必须 reconcile」的成本。

工程间隙: Guide 结构名与 mongodb-8.0 头文件可能局部重命名(例如队列条目类型前缀);排障以源码 src/evict/ 与 MongoDB 所带版本为准。本篇无 serverStatus / WT statistics 实测。

开放问题:

  1. 在更新密集 + 大 HS 窗口下,dirty_trigger 与 updates_trigger 谁先打满更常见?(需实验台账)
  2. HS 与用户表的 eviction 公平性阈值(第 08、15 篇)。

七、收束

  1. Eviction = server 近似 LRU 选页 + worker(或高压下的应用线程)执行。
  2. Clean 直接释放;dirty 必须 reconcile,最新进用户表、旧版进 HS。
  3. target/trigger(总量、dirty、updates)决定后台忙还是前台协助。

下一篇进入页上写路径:B-Tree 与 update chain——eviction/reconcile 要消化的,正是这些挂在 WT_PAGE_MODIFY 上的更新。


参考资料

规范 / 官方文档

源码

站内


上一篇Cache 与 WT_REF
下一篇B-Tree 与 update chain

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-07-22 · database / storage

【WiredTiger 内核】Reconciliation:内存页到 on-disk image

拆解 WiredTiger reconciliation:把 in-memory 页转为 on-disk image、按 leaf_page_max 与 split_pct 分裂,并在用户表 reconcile 时选出最新已提交值、将更旧更新写入 History Store;锚定 wiki 与 src/reconcile/。


By .