在mongo中删除数据并不会直接释放磁盘,而是产生很多碎片。这些碎片会被mongo继续利用。当有新数据插入时,会重复利用这些碎片,而不需要新申请磁盘空间。
但是这会导致的问题是,磁盘可能一直处于高水位的使用水平,对运维来说是一个定时炸弹。因为碎片只会被所属的库使用,但我们经常会新建很多库,这就导致磁盘越来越紧张。
目前我摸索出的是三种方法
1,将备节点清空,重新同步。
在备节点同步的过程中,碎片空间会被整理。备节点同步过去的是完全的数据和索引。
之后再进行一次主备切换。
使备节点成为主节点。
再将主节点数据清空,同步一次。
最终使主备都达到释放碎片的目的。
优点:服务一直可用
缺点:动作过大。要保证同步过程在同步窗口之内。建议将oplog尽量设置大一点
2,使用compact命令
compact是mongo中的压缩命令。可以整理删除数据产生的碎片。
在WiredTiger 数据库引擎下,该命令会将整理出的空间释放给操作系统。
在MMAPv1引擎下,compact会整理碎片,重建索引,但不会将未使用的空间释放给系统,后续新插入的数据依然可以使用这些空间
命令:
进入要执行的数据库
db.runCommand({ compact: <collection name>,force:<boolen> } )
对主备节点分别执行一次该命令
在复制集模式下的一些注意:
该命令会阻塞运行该命令的库,一定要选择好执行的时间
compact命令不会自动复制到secondary节点执行,compact在每个节点成员中都是独立的,在Primary,secondary中执行时都要使用force参数,
当在secondary的collection上执行compact命令时,此secondary节点会变成RECOVERING状态,且无法提供读操作
在capped collection中不必使用compact命令,因为它本身就是固定空间
实验:
当前库占了大约5.8G的磁盘
然后我删除了部分数据

shard1:PRIMARY> db.runCommand({ compact: "fs.files"} )
{
"ok" : 0,
"errmsg" : "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force"
}
需要加force:true
shard1:PRIMARY> db.runCommand({ compact: "fs.files",force:true} )
shard1:PRIMARY> db.runCommand({ compact: "fs.chunks",force:true} )
这里会卡很久,数据库操作会被锁住

实践证明:确实能够压缩
3,做repairDatabase
这个命令我没有尝试,谨慎使用。
做repairDatabase要求剩余磁盘要足够大。
但是当我的磁盘告警时,已经不会有足够的磁盘做repairDatabase了
db.runCommand({repairDatabase:1})
注:这个命令一定要谨慎使用,能不用的情况下尽量不用,因为会花费很多时间和性能
官网的一句话是这样说的:
The repairDatabase command compacts all collections in the database. It is identical to running the compact command on each collection individually
不建议直接repairDatabase,不如对需要做压缩的集合进行compact
总结
个人觉得mongo的这种机制真的很蛋疼。
大家还有没有什么好方法,欢迎交流
网友评论