【Mongo】数据删了磁盘空间但没有减少

Author:skate

Time:2023/10/22

一、问题描述

产线用户反馈,一个华为云的mongo实例磁盘空间告警,使用率超过90%(使用状况 1630.9/1800GB),让其通过数据库运维平台找到占用大空间的表,然后清理历史数据;用户清理数据后,发现使用的磁盘空间没有减少

二、问题分析

华为云mongo实例信息:

配置:| 2 vCPUs | 4GB

版本:4.0

存储引擎:WiredTiger

磁盘使用率:90.61%(使用状况 1630.9/1800 GB)

查看占用磁盘空间大的表

通过数据库运维平台查看如上三个表占用磁盘空间最大,而且数据逻辑大小远远小于数据占用的存储空间,说明数据清理产生了有大量的碎片;一般来说磁盘碎片会被数据库继续使用,当有新数据插入时,会重复利用这些碎片。

但是我们目前碎片占用空间太大,需要回收下

三、解决方案

可以通过如下命令回收集合的的磁盘碎片

db.runCommand({compact:"<collection_name>",force:true})

因为MongoDB 4.4及之前的版本执行compact命令会导致集合所属的数据库被锁定,且该数据库的读写操作将被阻塞,建议在业务低峰期操作,操作的步骤如下

1、先在备库执行compact命令

db.runCommand({compact:"<collection_name>"})

2、然后主备切换

3、在新的备库执行compact命令

db.runCommand({compact:"<collection_name>"})

A.阿里云的mongo实例说明

阿里云的mongo实例,如果需要compact,需要我们自己按如上步骤手工操作

B.华为云的mongo实例特殊说明:

默认华为云的mongo实例的管理员用户rwuser默认是没有执行compact权限的,如果需要执行这个命令,联系华为云工程师,让华为云工程师帮其在后台执行(或者升级mongo实例的小版本,向华为云申请开通compact命令权限),这个compact命令是低频的,目前命令提供给华为云执行即可。

RocksDB在删除数据后,将删除操作直接转化为追加写,在积攒了一定数据量的冗余数据后,会自动触发后台compact线程对同一数据的多版本进行归并聚合,从而释放多余的磁盘空间,因此建议等待系统自动回收。当磁盘空间使用率较高,接近只读状态阈值时,手工操作回收

WiredTiger在删除数据,进行数据多版本归并聚合后,也会空余出磁盘空间碎片,但wiredTiger并不会将这部分磁盘空间返还给操作系统,而是打上标记预留给当前collection后续的写入,此collection后续的写入会优先使用这部分预留的磁盘空间,如果需要释放这部分磁盘空间,可以尝试通过执行compact命令进行释放(注:此命令会阻塞正常业务)。

具体操作步骤:

1、通过数据库运维平台查看哪些集合占用磁盘空间大、碎片率高,碎片率超过50%就要注意了

2、在备库执行集合压缩命令(降低对主库的写操作的阻塞,在业务低峰期操作)

use tbm
db.runCommand({compact:"zjthStdTag"})     //耗时:424.702s (7.08min)
db.runCommand({compact:"ztzbStdTag"})   //耗时:379.738s (6.33min)
db.runCommand({compact:"hrkStdTag"})    //耗时:46.857s

3、主备库倒换

4、在新备库执行集合压缩命令

use tbm
db.runCommand({compact:"zjthStdTag"})
db.runCommand({compact:"ztzbStdTag"})
db.runCommand({compact:"hrkStdTag"})

把2-4步骤发给华为云工程师,让其在后台执行帮手工回收集合磁盘空间

四、结果收益

经过compact后,磁盘利用率从90%降低到25%,磁盘空间回收了1180G

---end---

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,可以使用MongoDB的异步驱动程序(Async Driver)来异步批量删除Mongo数据。以下是一个示例代码,可以演示如何使用异步驱动程序来批量删除Mongo数据: ``` // 引入异步驱动程序 import com.mongodb.async.client.MongoDatabase; import com.mongodb.async.client.MongoCollection; import com.mongodb.async.client.MongoClient; import com.mongodb.async.client.MongoClients; import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.FindIterable; import com.mongodb.async.client.MongoCursor; import org.bson.Document; // 创建异步客户端 MongoClient mongoClient = MongoClients.create(); // 获取异步数据库和集合 MongoDatabase database = mongoClient.getDatabase("your_database_name"); MongoCollection<Document> collection = database.getCollection("your_collection_name"); // 构造查询条件 Document query = new Document("your_query_key", "your_query_value"); // 执行查询操作 FindIterable<Document> iterable = collection.find(query); // 遍历查询结果,并异步删除 iterable.forEach(new Block<Document>() { @Override public void apply(Document document) { collection.deleteOne(document, new SingleResultCallback<Void>() { @Override public void onResult(Void result, Throwable t) { if (t != null) { System.out.println("Failed to delete document: " + t.getMessage()); } else { System.out.println("Deleted document: " + document.toJson()); } } }); } }, new SingleResultCallback<Void>() { @Override public void onResult(Void result, Throwable t) { if (t != null) { System.out.println("Failed to execute query: " + t.getMessage()); } else { System.out.println("Query executed successfully."); } } }); // 关闭异步客户端 mongoClient.close(); ``` 在上面的代码中,我们首先创建了异步MongoDB客户端,然后获取了异步数据库和集合。接下来,我们使用find()方法执行查询操作,然后遍历查询结果并异步删除每个文档。最后,我们关闭了异步客户端。请注意,异步操作是非阻塞的,因此需要为每个操作提供回调函数。 以上是一个简单的示例,以帮助你理解如何通过异步驱动程序来批量删除Mongo数据。实际上,您可能需要根据自己的具体需求进行更复杂的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值