一次MongoDB分页查询导致的OOM问题

OOM描述信息:

2018-09-18 14:46:54.338 [http-nio-8099-exec-8] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [/party-data-center] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: GC overhead limit exceeded] with root cause
java.lang.OutOfMemoryError: GC overhead limit exceeded
	at org.bson.io.ByteBufferBsonInput.readString(ByteBufferBsonInput.java:154)
	at org.bson.io.ByteBufferBsonInput.readString(ByteBufferBsonInput.java:126)
	at org.bson.BsonBinaryReader.doReadString(BsonBinaryReader.java:245)
	at org.bson.AbstractBsonReader.readString(AbstractBsonReader.java:461)
	at org.bson.codecs.BsonStringCodec.decode(BsonStringCodec.java:31)
	at org.bson.codecs.BsonStringCodec.decode(BsonStringCodec.java:28)
	at org.bson.codecs.BsonArrayCodec.readValue(BsonArrayCodec.java:102)
	at org.bson.codecs.BsonArrayCodec.decode(BsonArrayCodec.java:67)
	at org.bson.codecs.BsonArrayCodec.decode(BsonArrayCodec.java:37)
	at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
	at org.bson.codecs.configuration.LazyCodec.decode(LazyCodec.java:47)
	at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
	at org.bson.codecs.configuration.LazyCodec.decode(LazyCodec.java:47)
	at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
	at org.bson.codecs.configuration.LazyCodec.decode(LazyCodec.java:47)
	at org.bson.codecs.BsonArrayCodec.readValue(BsonArrayCodec.java:102)
	at org.bson.codecs.BsonArrayCodec.decode(BsonArrayCodec.java:67)
	at org.bson.codecs.BsonArrayCodec.decode(BsonArrayCodec.java:37)
	at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
	at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
	at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
	at com.mongodb.connection.ReplyMessage.<init>(ReplyMessage.java:51)
	at com.mongodb.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:301)

根据以上信息,好像是MongoDB查询数据的时候占用内存过大,导致的OOM

导出dump文件并且分析一下 使用MAT打开文件后有个 Problem Suspect 1(最有可能导致内存溢出的提示)

The thread org.apache.tomcat.util.threads.TaskThread @ 0xf9b19fa0 http-nio-8099-exec-8 keeps local variables with total size 58,255,056 (60.49%) bytes.
The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader>".
The stacktrace of this Thread is available. See stacktrace.


Keywords
java.lang.Object[]

Details »

点击 See stacktrace

信息量还是很庞大的,慢慢分析。 找到

at com.mongodb.DB.command(Lcom/mongodb/DBObject;Lcom/mongodb/ReadPreference;Lcom/mongodb/DBEncoder;)Lcom/mongodb/CommandResult; (DB.java:496)
  at com.mongodb.DB.command(Lcom/mongodb/DBObject;Lcom/mongodb/ReadPreference;)Lcom/mongodb/CommandResult; (DB.java:512)
  at com.mongodb.DB.command(Lcom/mongodb/DBObject;)Lcom/mongodb/CommandResult; (DB.java:467)

我们可以发现是执行Mongo命令出的错误,MongoResult,,,这不是返回的Mongo查询结果集吗??难道是返回的结果集过大??很有可能!!! 继续往下看。。。

at com.fosung.data.party.dao.DetailDao.detailQuery(Lcom/fosung/data/party/dto/PartyItemDto;)Lcom/fosung/data/party/vo/OutDetailCountVo; (DetailDao.java:314)
  at com.fosung.data.party.dao.DetailDao$$FastClassBySpringCGLIB$$caf49f16.invoke(ILjava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; (Unknown Source)

此处看到我们业务代码的方法,很有可能就是此处方法导致的OOM,进一步分析我们的业务方法: 经过我们仔细分析终于找出问题的原因: 上面出现问题的原因是在获取总条数的时候,没有加分页条件(skip和limit)导致查询所有符合条件的记录(符合条件的记录有6w多条),全部加载到内存中,因此导致了OOM问题。

解决: MongoDB使用管道查询后获取符合条件的总条数

db.getCollection('user_order').aggregate([
     { "$match" : { "code" : "100002255842358"}} , 
     { "$project" : { "code" : 1 , "yearInfo" : 1 , "personInfo" : 1}} , 
     { "$unwind" : "$yearInfo.counts"} , 
     { "$unwind" : "$yearInfo.counts.code"} , 
     { "$match" : { "yearInfo.counts.code" : { "$in" : [ "1"]}}} , 
     { "$sort" : { "code" : 1 , "yearInfo.counts.sort" : 1}} ,
     { "$lookup" : { "from" : "user_info" , "localField" : "yearInfo.counts.detail" , "foreignField" : "_id" , "as" : "personInfo"}} , 
     { "$unwind" : "$personInfo"} , 
      {"$group":{"_id":null,"totalCount":{"$sum":1}}},
      {"$project":{"totalCount":"$totalCount","_id":0}}
    ])

不需要每次去获取所有记录数,再取记录的条数。

修改完后测试完美通过。。。

转载于:https://my.oschina.net/u/2477500/blog/2054701

MongoDB中进行分页查询可以通过使用MongoDB分页插件来实现。首先,需要配置MongoDB的相关信息。在配置类中使用@Configuration注解标记,并使用@Autowired注解将MongoTemplate注入进来。然后,使用@Bean注解标记一个方法,返回MongoPageHelper实例,该实例需要传入MongoTemplate对象作为参数。这样就完成了MongoDB配置的准备工作。 接下来,需要使用正确的分页办法来实现分页查询。在MongoDB中,推荐的分页解决方案是先查询当前页的第一条数据,然后按顺序查询pageSize条数据。这样可以提高查询的效率。 如果你想使用开箱即用的分页能力,可以使用MongoDB分页插件。该插件为MongoDB提供了方便的分页功能。你可以在我的博客中找到如何使用Maven引入该插件的详细信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [MongoDB分页的Java实现和分页需求的思考](https://blog.csdn.net/weixin_34303897/article/details/86400025)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [mongo-page-helper:MongoDB分页插件](https://download.csdn.net/download/weixin_42098759/18715448)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值