跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

MongoDB 事务为何消耗大量内存_监控 WiredTiger 缓存压力与事务长连接

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 范围扩大。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 使用场景差异: 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 —— 这种隐式开销最难预估。

相关文章