WiredTiger cache在事务期间因快照锁定无法驱逐页面而突增,导致内存占用飙升甚至溢出;应监控cache使用率、避免全量扫描与外部阻塞、强制事务终结、限制事务时长并合理复用会话。

事务执行期间 WiredTiger cache 占用突增
MongoDB 事务本身不直接分配内存,但所有读写操作都经由 WiredTiger 存储引擎的 cache(默认最大 50% 物理内存)。开启多文档事务后,WiredTiger 必须为整个事务生命周期内涉及的所有数据页保留 snapshot —— 这些页面不能被 evict,直到事务结束或回滚。这意味着一个运行 30 秒、扫描 200 万文档的事务,可能长期 hold 住数百 MB 甚至数 GB 的 cache 页面。
实操建议:
- 用
db.serverStatus().wiredTiger.cache查看实时 cache 使用:重点关注bytes currently in the cache和maximum bytes configured比值,持续 >85% 就有风险 - 事务中避免
find().toArray()或全集合扫描;改用带.limit()和合理.sort()的游标分批处理 - 不要在事务里调用耗时外部 API 或 sleep —— 这会让 snapshot 无谓延长
长连接 + 未关闭事务导致 cache 泄漏
客户端开启事务后未显式调用 session.commitTransaction() 或 session.abortTransaction(),且连接未断开,WiredTiger 会认为该事务仍“活跃”,对应 snapshot 一直锁住 cache 中的数据页。即使客户端进程已僵死,只要 TCP 连接未超时(默认 net.ipv4.tcp_fin_timeout=60s,MongoDB socketTimeoutMS 默认 30000ms),cache 就不会释放。
常见错误现象:
-
db.currentOp({ "secs_running": { "$gt": 30 }, "transactionState": "inProgress" })返回大量长时间运行事务 -
mongostat显示netIn/netOut极低,但mem使用率持续攀升 - 日志中反复出现
WT_CACHE_FULL: operation would overflow cache
实操建议:
- 所有事务代码必须包裹
try/catch/finally,并在finally块强制调用abortTransaction() - 服务端配置
transactionLifetimeLimitSeconds(默认 60),超过即自动 abort —— 但注意这不释放 client 端连接,需配合连接池 maxIdleTimeMS 使用 - 监控
currentOp中secs_running> 10s 的事务,告警并自动 kill(db.killOp(...))
事务嵌套与会话复用加剧 cache 压力
MongoDB 不支持真正嵌套事务,但开发者常误用同一 ClientSession 多次调用 startTransaction()。此时 WiredTiger 实际维持的是最外层事务的 snapshot,而中间的“子事务”只是逻辑标记 —— 结果是 cache 被更长时间锁定,且出错时 rollback 范围扩大。
使用场景差异:
- HTTP 请求级事务:每个请求新建 session,结束后立即 close —— 安全但开销略高
- 长连接 RPC 服务(如 gRPC):复用 session 但严格限制单 session 单事务,且每次事务后
endSession()
性能影响:
- 复用 session 但未 endSession → session 对象持续引用 cache snapshot → 内存无法回收
- 并发事务数 × 平均事务数据集大小 ≈ 潜在 cache 占用下限,这个值应远低于
wiredTigerCacheSizeGB
如何验证某次事务是否真的触发了 cache 溢出
不能只看 serverStatus 的总量,要定位具体哪类操作在吃 cache。WiredTiger 提供细粒度统计项,关键路径是:db.serverStatus().wiredTiger.cache["tracked dirty bytes in the cache"] 和 "pages evicted because they exceeded the in-memory maximum"。
实操步骤:
- 事务前执行
db.runCommand({ "setParameter": 1, "wiredTigerEngineConfigString": "verbose=[evict]" })(仅开发环境,生产慎用) - 复现事务,观察 mongod 日志是否密集出现
WT_VERB_EVICT+cache overflow - 对比两次
db.serverStatus().wiredTiger.cache,若pages requested from the cache增幅远大于pages written from cache,说明读密集型事务正在挤占空间
容易被忽略的是:即使事务只写入少量文档,只要它读取了大索引(比如 db.collection.find({ status: "pending" }).sort({ createdAt: 1 })),WiredTiger 仍需将整个索引 B-tree 路径载入 cache 并锁定 snapshot —— 这种隐式开销最难预估。











