MongoDB删除数据空间没有释放原因分析-碎片
一、现象简介
我们在做MongoDB数据库运维的时候,经常会发现数据库批量删除数据之后,磁盘空间并没有立即释放的场景。接下来我们就针对该场景进行分析。
二、问题复现
2.1 环境和数据准备
(1)初始指标记录
[root@10-27-0-224 ~]# du -h --max-depth=1 /data/db   # 查看初始MongoDB数据目录文件大小
32K	/data/db/journal
0	/data/db/_tmp
81M	/data/db
[root@10-27-0-224 ~]# df -TH                         # 查看初始磁盘使用率
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/vda1      xfs        22G  2.0G   20G  10% /
devtmpfs       devtmpfs  960M     0  960M   0% /dev
tmpfs          tmpfs     971M     0  971M   0% /dev/shm
tmpfs          tmpfs     971M   19M  953M   2% /run
tmpfs          tmpfs     971M     0  971M   0% /sys/fs/cgroup
tmpfs          tmpfs     195M     0  195M   0% /run/user/0
> db.serverStatus().mem       # 查看mongo内存使用情况
{
	"bits" : 64,
	"resident" : 51,
	"virtual" : 472,
	"supported" : true,
	"mapped" : 80,
	"mappedWithJournal" : 160
}
[root@10-27-0-224 ~]# mongostat
insert query update delete getmore command flushes mapped  vsize   res faults idx miss % qr|qw ar|aw netIn netOut conn     time
    *0    *0     *0     *0       0     1|0       1  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:16
    *0    *0     *0     *0       0     1|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:17
    *0    *0     *0     *0       0     1|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:18
    *0    *0     *0     *0       0     1|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:19
    *0    *0     *0     *0       0     2|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0  133b    10k    1 02:28:20
    *0    *0     *0     *0       0     1|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:21
    *0    *0     *0     *0       0     1|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:22
    *0    *0     *0     *0       0     1|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:23
    *0    *0     *0     *0       0     1|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0   79b    10k    1 02:28:24
    *0    *0     *0     *0       0     2|0       0  80.0M 472.0M 51.0M      0          0   0|0   0|0  133b    10k    1 02:28:25
    
# 其中内存相关字段的含义是:
- mapped:映射到内存的数据大小
- visze:占用的虚拟内存大小
- res:占用的物理内存大小
【注】如果操作不能在内存中完成,结果faults列的数值不会是0,视大小可能有性能问题。(2)批量插入100w测试数据
> for (var i = 1; i <= 1000000; i++) {
    db.starcto.insert( { x : i , name: "A", name1:"B", name2:"C", name3:"D"} )
}
> db.starcto.count()
1000000(3)导入数据后的指标记录
[root@10-27-0-224 ~]# du -h --max-depth=1 /data/db
76M	/data/db/journal
0	/data/db/_tmp
620M	/data/db
[root@10-27-0-224 ~]# df -TH
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/vda1      xfs        22G  2.6G   19G  12% /
devtmpfs       devtmpfs  960M     0  960M   0% /dev
tmpfs          tmpfs     971M     0  971M   0% /dev/shm
tmpfs          tmpfs     971M   19M  953M   2% /run
tmpfs          tmpfs     971M     0  971M   0% /sys/fs/cgroup
tmpfs          tmpfs     195M     0  195M   0% /run/user/0
> db.serverStatus().mem
{
	"bits" : 64,
	"resident" : 225,
	"virtual" : 1401,
	"supported" : true,
	"mapped" : 544,
	"mappedWithJournal" : 1088
}
[root@10-27-0-224 ~]# mongostat
insert query update delete getmore command flushes mapped vsize    res faults idx miss % qr|qw ar|aw netIn netOut conn     time
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:38
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:39
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:40
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:41
    *0    *0     *0     *0       0     2|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0  133b    10k    2 02:40:42
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:43
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:44
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:45
    *0    *0     *0     *0       0     1|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0   79b    10k    2 02:40:46
    *0    *0     *0     *0       0     2|0       0 544.0M  1.4G 225.0M      0          0   0|0   0|0  133b    10k    2 02:40:472.2 删除插入的100w测试数据
(1)删除集合数据
> use test switched to db test > show collections starcto system.indexes > db.starcto.drop() true > db.starcto.count() 0
(2)查看删除集合后的指标记录
[root@10-27-0-224 ~]# du -h --max-depth=1 /data/db
76M	/data/db/journal
0	/data/db/_tmp
620M	/data/db
[root@10-27-0-224 ~]# df -TH
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/vda1      xfs        22G  2.6G   19G  12% /
devtmpfs       devtmpfs  960M     0  960M   0% /dev
tmpfs          tmpfs     971M     0  971M   0% /dev/shm
tmpfs          tmpfs     971M   19M  953M   2% /run
tmpfs          tmpfs     971M     0  971M   0% /sys/fs/cgroup
tmpfs          tmpfs     195M     0  195M   0% /run/user/0
> db.serverStatus().mem
{
	"bits" : 64,
	"resident" : 225,
	"virtual" : 1402,
	"supported" : true,
	"mapped" : 544,
	"mappedWithJournal" : 1088
}
【注】由此可见MongoDB物理空间没有丝毫变化。三、问题分析
3.1 查询官网资料
MongoDB4.0及以下:https://docs.mongodb.com/v4.0/reference/method/db.repairDatabase/index.html

MongoDB4.2及以上 :https://docs.mongodb.com/v4.2/release-notes/4.2-compatibility/index.html

【注】通过对官网的文档查阅不难发现,MongoDB删除集合数据,物理磁盘空间不会直接释放,即使drop collections也无济于事。除非drop databases。在MongoDB4.0及以下,官网提供了一种回收MongoDB磁盘空间的方法,即 db.repairDatabase(),但该操作有一定的风险性,如上图。注意MongoDB4.0以上版本 db.repairDatabase()方法已经被废弃。
3.2 repairDatabase()回收磁盘空间
> db.repairDatabase()
{ "ok" : 1 }
 
> show dbs      # 空间已经释放
local  0.078GB
test   0.078GB
[root@10-27-0-224 ~]# du -h --max-depth=1 /data/db
0	/data/db/journal
0	/data/db/_tmp
0	/data/db/test
161M	/data/db
[root@10-27-0-224 ~]# df -TH
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/vda1      xfs        22G  2.3G   20G  11% /
devtmpfs       devtmpfs  960M     0  960M   0% /dev
tmpfs          tmpfs     971M     0  971M   0% /dev/shm
tmpfs          tmpfs     971M   19M  953M   2% /run
tmpfs          tmpfs     971M     0  971M   0% /sys/fs/cgroup
tmpfs          tmpfs     195M     0  195M   0% /run/user/0
[root@10-27-0-224 ~]# mongostat 
insert query update delete getmore command flushes mapped  vsize   res faults idx miss % qr|qw ar|aw netIn netOut conn     time
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:36
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:37
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:38
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:39
    *0    *0     *0     *0       0     2|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0  133b    10k    2 03:32:40
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:41
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:42
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:43
    *0    *0     *0     *0       0     1|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0   79b    10k    2 03:32:44
    *0    *0     *0     *0       0     2|0       0 160.0M 634.0M 71.0M      0          0   0|0   0|0  133b    10k    2 03:32:45
    
> db.serverStatus().mem
{
	"bits" : 64,
	"resident" : 71,
	"virtual" : 634,
	"supported" : true,
	"mapped" : 160,
	"mappedWithJournal" : 320
}四、总结
为解决MongoDB删除集合空间不释放的问题,总结以下方案:
4.1 数据导出再导入dump & restore
通过mongodump备份数据,mongorestore恢复数据,mongodump备份时间与数据大小成正比,所以该方案只适用实例数据比较少的情况,如果数据量非常大,该方法就需要长时间停业务,对于线上业务是不可接受的。
4.2 修复数据库repairDatabase()
db.repairDatabase()操作需要停业务进行,因为MongoDB会锁库直到 repair 操作完成。另外,必须注意预留足够的磁盘空间,需要额外一倍的空间,如果MongoDB 占用数据磁盘了100G,那么 repair 时还需要额外的100G+2G 空间。也可以追加磁盘,然后将目标目录指向新加的磁盘。
(1)操作方法一
mongod --dbpath /data/db --repair --repairpath /data/dbrepair
(2)操作方法二
db.repairDatabase()
或
db.runCommand({ repairDatabase: 1 })【注意】在生产上操作如果意外停止可能会造成数据无法恢复的危险。
4.3 复制数据库 db.copydatabase
db.copyDatabase("db1","db2","127.0.0.1:27017");复制出一个新的db2数据库,这个已经是最小数据占用的数据。会在数据目录下产生db2的相关数据文件。127.0.0.1:27017是db1的数据库所在的地址和端口号。copy完成后,可以删除db1,然后将db2修改回db1。
作者:UStarGao
链接:https://www.starcto.com/mongodb/194.html
来源:STARCTO
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
UCloud云平台推荐
随便看看
- 2021-07-03Linux安全—jumpserver跳板机
- 2021-09-20MySQL半同步复制与刷盘策略
- 2021-04-16MySQL innodb_buffer_pool_size参数优化
- 2022-05-08Prometheus+Grafana监控Docker容器
- 2021-10-08Microsoft SQL Server安装部署教程



