Mongo数据库吃内存问题以及解决情况

本文介绍了MongoDB如何使用内存及导致内存占用过高的原因。通过分析发现,MongoDB使用内存映射存储引擎,会占用服务器上的大量内存。文章提供了监控内存使用情况的方法,并给出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

起因

最近一直跑得好好的项目总是会莫名其妙的停了服务,最初的时候没有在意这个情况,觉得可能只是一个意外而已,可连着发生了好几次,就觉得有点怪异了,然后查看tomcat的log文件,就发现了问题所在了,内存不足

当时还觉得有点不理解,应该这台服务器的配置还是很高的,然后服务器上也只是跑了两个tomcat和一个mongo数据库,觉得不应该有这种问题的,然后就去查了一下资料,原来是mongo数据库在作祟,然后自己也用命令去查看了一下

真是不看不知道,一看吓一跳,一个mongo数据库占了服务器超过一半的内存,厉害的时候可以到70多,这时候才知道mongo吃内存的严重了。

MongoDB如何使用内存

        目前,MongoDB使用的是内存映射存储引擎,它会把磁盘IO操作转换成内存操作,如果是读操作,内存中的数据起到缓存的作用,如果是写操作,内存还可以把随机的写操作转换成顺序的写操作,总之可以大幅度提升性能。mongodb并不干涉内存管理工作,而是把这些工作留给操作系统的虚拟缓存管理器去处理,这样的好处是简化了MongoDB的工作,但坏处是你没有方法很方便的控制MongoDB占多大内存,事实上MongoDB会占用所有能用的内存,所以最好不要把别的服务和MongoDB放一起。


有时候,即便MongoDB使用的是64位操作系统,也可能会遭遇臭名昭著的OOM问题,出现这种情况,多半是因为限制了虚拟内存的大小所致,可以这样查看当前值:

大部分人都会和我一样,那就很好,如果不是的,可以自己修改过来:

不过要注意的是,ulimit的使用是有上下文的,最好放在MongoDB的启动脚本下。

       有时候,出于某些原因,你可能想释放掉MongoDB占用的内存,不过前面说了,内存管理工作是由虚拟内存管理器控制的,所以通常你只能通过重启服务来释放内存,你一定不齿于这样的方法,幸好可以使用MongoDB内置的closeAllDatabases命令达到目的:

当然,通过调整内核参数drop_caches也是可以释放缓存的:

平时可以通过mongo命令行来监控MongoDB的内存使用情况,如下所示:

还可以通过mongostat命令来监控MongoDB的内存使用情况,如下所示:

其中内存相关字段的含义是:

mapped:映射到内存的数据大小 


仅以该文让自己以后再遇该类问题可以有据可依,也让他人不再困惑于这个问题上


### 在 MongoDB 中删除重复文档只保留一条的方法 为了在 MongoDB 中找到并删除重复的文档,仅保留每组的一条记录,可以通过 `aggregate` 和 `$group` 来识别重复项,并利用 `_id` 字段唯一性来决定哪些记录需要被移除。 以下是具体的操作方式: #### 使用 Aggregation Framework 找到重复数据 首先,使用聚合框架(Aggregation Framework)定位具有相同字段组合的重复记录。假设我们希望基于 `firstField` 和 `secondField` 进行去重,则可以执行如下命令[^1]: ```javascript db.collection.aggregate([ { $group: { _id: { firstField: "$firstField", secondField: "$secondField" }, uniqueIds: { $push: "$_id" }, count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ]) ``` 此查询会返回一组对象,其中每一组都表示存在重复的关键字组合及其对应的 `_id` 列表。如果某个关键字组合下的记录数大于 1,则认为它们是重复的。 #### 删除多余的副本 一旦获得了上述结果集,就可以编写脚本来批量删除多余副本而留下单个实例。这里给出一种 JavaScript 脚本形式完成这一目标: ```javascript // 获取所有重复项分组的结果 var duplicates = db.collection.aggregate([ { $group: { _id: { firstField: "$firstField", secondField: "$secondField" }, uniqueIds: { $addToSet: "$_id" }, count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ]); duplicates.forEach(function(doc) { // 对于每一个重复集合,保留第一个ID其余全部删掉 doc.uniqueIds.shift(); // 移除首个元素作为要保存的那个 db.collection.remove({ _id: { $in: doc.uniqueIds } }); }); ``` 以上代码片段实现了遍历所有的重复项目列表并将除了第一条之外的所有其他匹配项从数据库中清除出去的目的^。 需要注意的是,在实际应用过程中可能还需要考虑性能优化以及事务处理等问题以确保大规模生产环境下的稳定性与一致性。 另外值得注意的是,尽管这种方法能够有效解决问题,但如果涉及到非常庞大的数据量或者频繁发生的更新操作场景下可能会带来一定的负担。因此建议定期维护索引结构并且合理规划存储策略从而减少此类情况的发生几率[^2]. 最后提醒一点就是当尝试运行某些特定类型的查询比如distinct时有可能遇到内存限制错误提示如:“distinct failed: MongoError: distinct too big, 16mb cap”,此时则需调整查询逻辑改用更高效的方式来进行统计计算而不是单纯依赖内置函数达成目的[^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值