MongoDB删除数据后磁盘空间不释放是WiredTiger引擎的正常行为,仅标记空间为“可复用”而不返还操作系统;需显式执行compact命令(先fs.chunks后fs.files)或dump/restore才能物理回收空间。

删除大量数据后磁盘空间不释放,不是 bug,是 WiredTiger 的正常行为:它只标记空间为“可复用”,不主动还给操作系统。想让 df -h 看到空间下降,必须显式触发物理回收。
compact 命令为什么必须分两步执行 fs.chunks 和 fs.files
GridFS 实际由两个集合协同工作:fs.files 存元数据(小),fs.chunks 存二进制分片(大,通常占 90%+ 空间)。WiredTiger 的 compact 是按集合粒度操作的,且不会跨集合识别“孤儿 chunk”。
-
db.runCommand({compact: "fs.chunks"})必须先执行——它处理真正占空间的主体,但前提是这些 chunk 在fs.files中有对应记录;否则会被跳过 -
db.runCommand({compact: "fs.files"})必须后执行——清理元数据索引碎片,否则残留的索引项可能阻碍后续 chunk 复用 - 如果只 compact
fs.files,fs.chunks里一堆无主分片(orphaned chunks)完全不受影响,磁盘占用纹丝不动
compact 在 replica set 上为什么必须连 primary 执行
WiredTiger 的 compact 操作会重写底层 .wt 文件,涉及文件系统级操作,secondary 节点默认是只读的,且不持有写锁权限。
- 在 secondary 上执行
db.runCommand({compact: "fs.chunks"})返回{ "ok": 1 },但实际什么都没做——日志里也几乎不报错 - 必须用
rs.isMaster()确认当前连接的是 primary;若不确定,先rs.status()查stateStr: "PRIMARY" - Atlas 或其他托管服务可能禁用
compact,需查其文档;部分平台会后台自动快照,导致 compact 后df -h延迟数分钟才更新
compact 失败或无效时,dump/restore 是更可靠的替代方案
当 wiredTiger-block-manager-file bytes available for reuse 仍远高于预期(比如 >50% 总大小),说明碎片已严重离散,compact 效率急剧下降。
- 停写或切到维护窗口,用
mongodump --db yourdb --collection fs.chunks --collection fs.files导出 - 执行
db.fs.chunks.drop()和db.fs.files.drop()——注意不是remove({}),那是逻辑删,留坑 - 用
mongorestore --drop恢复;WiredTiger 会新建紧凑的.wt文件,空间利用率回归基线 - 全程需要 ≥ 当前数据库总大小的额外磁盘空间;副本集可先在 secondary dump + restore,再切换 primary,实现近零停机
最容易被忽略的其实是“孤儿 chunk”问题:有人清空了 fs.files 却没清理 fs.chunks,或者误以为 TTL 索引能自动清理碎片——WiredTiger 默认不建 TTL 索引,历史 chunk 不会过期,compact 也扫不到它们。


















