GridFS 删除后磁盘空间不降,本质是 WiredTiger 仅标记空间为“可复用”而不返还 OS;需先 compact fs.chunks,再 compact fs.files,且必须在 primary 执行,否则无效。

GridFS 删除后磁盘空间不降,本质是 WiredTiger 没还空间给 OS
执行 delete 或 remove GridFS 文件,只是从 fs.files 和 fs.chunks 两个集合里删掉文档,WiredTiger 引擎不会立刻把底层磁盘块返还操作系统。它只把空间标记为“可复用”,后续插入新 chunk 时优先填这里——所以 df -h 看不到变化,mongostat 的 mapped 值也基本不动。
db.runCommand({compact: "fs.chunks"}) 是最直接的物理回收手段
必须分步 compact,且顺序不能错:
-
db.runCommand({compact: "fs.chunks"})—— 先 compact 这个,它占空间绝对大,通常 >90% - 再
db.runCommand({compact: "fs.files"})—— 元数据小,但不 compact 会残留索引碎片 - 命令必须连到 replica set 的
primary节点执行;secondary 上执行无效 - compact 期间会重写 .wt 文件,磁盘临时占用可能翻倍,务必确认有足够空闲空间(至少预留原
fs.chunks大小的 1.2 倍) - 该操作阻塞写入,建议在低峰期执行;可用
db.currentOp({secs_running: {$gt: 10}})监控是否卡住
compact 失败或效果差?别硬扛,换 dump/restore
当 compact 后 wiredTiger-block-manager-file bytes available for reuse 仍远高于预期,说明碎片太散或文件已严重膨胀,此时 compact 效率极低。应转向重建:
- 停写或切到维护窗口,用
mongodump --db yourdb --collection fs.chunks --collection fs.files导出 - 执行
db.fs.chunks.drop()和db.fs.files.drop()清空集合(注意:不是remove({}),那是逻辑删) - 用
mongorestore恢复,WiredTiger 会重新分配紧凑的 .wt 文件 - 副本集环境下,可在 secondary 上 dump + restore,再切换 primary,实现近零停机
- 全程需额外磁盘空间 ≥ 当前数据库总大小,不可省略
最容易被忽略的两个坑
很多人执行了 compact 却发现空间还是没下来,问题往往卡在这两点:
- 只删了
fs.files文档,却忘了同步清理fs.chunks—— 孤儿 chunk 不会被 compact 扫到,永远占着磁盘 - 误以为
db.fs.files.remove({})就等于“清空 GridFS”,结果fs.chunks里一堆无主分片,compact 根本不处理它们 - 没检查
fs.chunks是否建了 TTL 索引;默认没有,历史碎片不会自动过期 - 在 Atlas 或其他托管服务上执行 compact,可能被后台快照机制延迟生效,甚至被平台禁止(需查文档或联系支持)
真正释放空间的动作,从来不是删文档那一下,而是你有没有让 WiredTiger 重排物理页。compact 是最轻量的路径,但前提是它能扫到所有要整理的数据。











