【WiredTiger 内核】History Store 与 Durable History:文档库里的第三种 MVCC

💡 原文中文,约10400字,阅读约需25分钟。
📝

内容提要

WiredTiger通过History Store实现MVCC:用户表仅存最新已提交版本,旧版本存入独立的WiredTigerHS.wt文件。读路径按update chain→磁盘页→History Store顺序查找。相比Lookaside,Durable History提供跨eviction/checkpoint的可查询历史契约,由minSnapshotHistoryWindowInSeconds控制保留窗口。与PG堆版本、InnoDB undo相比,WT将当前与历史分离,利于用户页驱逐,但增加历史I/O与磁盘开销。

🔎

延伸解读

历史存储的代价:读放大与磁盘开销

WiredTiger 将旧版本移入独立的 History Store,虽然让用户表页更易驱逐,但读旧快照时需额外查找旁路表,可能增加 I/O。同时,文档更新常以整份旧 BSON 作为历史载荷,导致 WiredTigerHS.wt 体积增长,与“只改一个字段”的直觉不符。因此,评估磁盘需求时,应基于更新大小和频率,而非仅看 cacheSizeGB。

Durable History 与 Lookaside 的本质区别

MongoDB 4.4 起,WiredTiger 用 History Store 取代 Lookaside,不仅是文件改名。Lookaside 更接近 cache overflow,重启后行为不明确;而 History Store 是正式表,提供跨 eviction 和 checkpoint 的可查询历史契约,由 minSnapshotHistoryWindowInSeconds 控制保留窗口。运维痛点从 LAS 无限膨胀转为 HS 体积与窗口参数的权衡。

MVCC 落点对比:三种引擎的取舍

PostgreSQL 在堆内保留多版本,导致表膨胀;InnoDB 用 undo log 旁路,但 undo 过长会拖慢 purge;WiredTiger 将历史独立存储,利于用户页驱逐,却引入第二棵 B-Tree 的缓存竞争。三者语义目标相近,但物理布局不同,故障模式各异:PG 表膨胀、InnoDB undo 历史过长、WT 的 HS 文件与窗口参数。

Q&A

WiredTiger的History Store是什么?它和Lookaside有什么区别?

History Store是WiredTiger在MongoDB 4.4+中引入的持久化历史版本存储,用于实现MVCC。它将用户表中的旧版本数据移入独立的WiredTigerHS.wt文件,而用户表只保留最新已提交版本。与Lookaside(LAS)相比,History Store是正式的数据库表,提供跨eviction和checkpoint的可查询历史契约,而LAS更偏向cache overflow的swap机制,重启后行为不同。

WiredTiger中旧版本数据是如何存储和管理的?

WiredTiger将旧版本数据存储在全局的History Store表中,文件名为WiredTigerHS.wt。用户表只保存最新已提交版本,旧版本在reconciliation时写入History Store。History Store的键包含btree ID、record key、start timestamp和counter,值包含stop timestamp、durable timestamp、update type和value。回收由oldest timestamp和minSnapshotHistoryWindowInSeconds控制。

WiredTiger的读路径是如何查找旧版本的?

WiredTiger的读路径按顺序查找:首先在内存的update chain中查找对当前事务可见的更新;如果没有,则检查磁盘页上的版本是否可见;如果仍不可见,则进入History Store,从该键的最新条目向更旧方向迭代,直到找到满足读时间戳和事务可见性的版本。如果找不到,则返回WT_NOTFOUND。

minSnapshotHistoryWindowInSeconds参数的作用是什么?

minSnapshotHistoryWindowInSeconds是MongoDB 5.0引入的参数,用于控制WiredTiger History Store中快照历史的保留窗口。窗口越大,磁盘上保留的旧修改值时间越长,但磁盘空间占用也随之增加。它决定了历史版本何时可以被回收,是运维人员调整历史保留策略的显式旋钮。

WiredTiger的History Store与PostgreSQL的堆版本、InnoDB的undo log在MVCC实现上有何不同?

三种引擎的MVCC实现不同:PostgreSQL在堆表中保留新旧元组,旧版本通过版本链和VACUUM回收;InnoDB将旧版本存储在undo log中,通过purge线程回收;WiredTiger则将旧版本存储在独立的History Store表中,用户表只保留最新值。WiredTiger将当前与历史分离,有利于用户页的eviction,但增加了历史I/O和磁盘开销。

WiredTiger的History Store在reconciliation时是如何写入的?

在reconciliation过程中,WiredTiger检查update chain,选出最新已提交更新作为用户表的on-disk值,而尚未过时的更旧更新则写入History Store。具体由__wt_hs_insert_updates函数实现,它会将边界上保存的更新列表拷贝到History Store中。如果用户表页上没有需要保存的更新,则不会写入History Store。

WiredTiger的History Store文件(WiredTigerHS.wt)为什么会不断增长?如何管理?

WiredTigerHS.wt的增长主要因为旧版本数据持续写入,其大小受更新频率、更新大小和minSnapshotHistoryWindowInSeconds参数影响。管理方式包括调整保留窗口、监控长事务和复制延迟,而不是手动删除文件。官方手册强调不要手工修改或删除WiredTigerHS.wt,空间问题应通过调整参数和优化业务读模型来解决。

🏷️

标签

➡️

继续阅读