直接运行db.serverstatus().wiredtiger.cache,若bytes currently in the cache / maximum bytes configured持续>85%且db.serverstatus().metrics.transaction.currentactive≥3,即可快速判定事务正塞满wiredtiger cache。

怎么快速判断事务正在塞满WiredTiger cache
直接运行 db.serverStatus().wiredTiger.cache,重点看两个字段:bytes currently in the cache 和 maximum bytes configured。前者除以后者,如果持续 > 85%,说明 cache 已吃紧;再结合 db.serverStatus().metrics.transaction.currentActive,若该值 ≥ 3 且持续不降,基本可锁定是事务导致的缓存淤积。
常见误判点:bytes dirty in the cache cumulative 是自启动以来的累计写入量,不是当前脏页大小,别拿它当水位指标。
- 用
mongostat观察实时 %used 和 %dirty:同时 > 95% 和 > 20% 是高危信号 - 查长事务:
db.currentOp({ "secs_running": { "$gt": 10 }, "transactionState": "inProgress" }) - 注意
netIn/netOut极低但mem持续爬升——这往往是事务卡住、快照死锁 cache 的典型表现
为什么事务一开,cache 就涨得飞快
MongoDB 事务不额外分配内存,但它强制 WiredTiger 在整个事务生命周期内保留所有被修改文档的**全量旧版本快照**。一个 updateOne 修改 1000 条、每条平均 1.5MB 的文档,光快照就占 1.5GB,还不算索引更新和日志缓冲。
- 事务中用了
readConcern: "snapshot"或writeConcern: { w: "majority" }?会延长快照保留时间,加剧堆积 - 事务里调了外部 HTTP 接口或
sleep(5000)?快照无谓驻留,cache 不释放 - 用了
find().toArray()扫全集合?未命中索引时,大量 page 被加载进 cache 却无法 evict - 客户端开了事务但没调
session.commitTransaction()或session.abortTransaction()?只要连接没断,WiredTiger 就认为事务仍活跃
如何安全地压事务粒度与提交频率
事务不是不能用,而是不能“大、长、密”一起上。单事务写入建议控制在 1–5MB 数据量以内,执行时间尽量 ≤ 2 秒,避免每秒开启上百个短事务。
- 拆批:把 bulkWrite 拆成每批 100–500 条,中间显式提交
- 加超时:服务端设
transactionLifetimeLimitSeconds: 30(需 MongoDB ≥ 4.2),防僵死 - 兜底清理:所有事务代码必须包在
try/catch/finally中,finally强制调abortTransaction() - 禁用危险组合:避免
readConcern: "snapshot"+ 大范围$lookup或aggregate()
eviction 线程调优和 cacheSizeGB 设置要不要动
先看是否真有必要调。默认 threads_max=4 通常够用;只有在 %dirty > 20% 持续不降、且已确认事务粒度合理时,才考虑微调 eviction 线程。
调 cacheSizeGB 更要谨慎:它只影响 WiredTiger 最大可用内存,不是“越大越好”。云数据库(如腾讯云 MongoDB)已将 cache 限制为实例内存规格的 60%,你改配置文件也无效。
- 调线程数命令(仅副本集 4.0+):
db.runCommand({"setParameter":1, "wiredTigerEngineRuntimeConfig":"eviction=(threads_max=6,threads_min=2)"}) - 本地部署可调
storage.wiredTiger.engineConfig.cacheSizeGB,建议设为物理内存的 50%–60%,SSD 可放宽至 70% - 调完不重启不生效;但线上改
cacheSizeGB需停服,风险高,优先从事务逻辑入手











