mongodb java driver readFully很慢

时间:2014-08-11 13:53:52

标签: mongodb

在我的应用程序中使用mongodb java驱动程序(最新)的db.collection.find非常慢。我调查了其中一个如下

// about 300 hundred ids at a time (i've tried lower and higher numbers - no impact
db.users.find({_id : {$in : [1,2,3,4,5,6....]}}) 

一旦我得到光标,我会做:cursor.toArray(),然后迭代结果

toArray操作非常慢。他们平均需要大约一分钟。重要提示:我的数据库始终处于非常繁重的负载状态。这个特殊的系列有超过50毫米的条目。

我已将mongo java驱动程序中的问题缩小到com.mongodb.Response - 特别是这一行:

 final byte [] b = new byte[36];
 Bits.readFully(in, b);

令人难以置信的只有36个字节的读取有时需要一分钟!

当我为数据库带来负担时,改进非常激烈。从大约一分钟到5-6秒。我的意思是5-6秒获得300个文件仍然超级慢,但肯定比1分钟更好。

我可以做些什么来进一步解决这个问题?我需要查看MondoDB上的设置吗?

2 个答案:

答案 0 :(得分:0)

会发生什么

您正在加载所有300个用户文档。

搜索_id索引并将相应文档完全发送到您的应用程序会发生什么。因此,mongoDB将访问它的数据文件,读取第一个文档并将其发送给您,然后它跳转到下一个文档并将其发送给您,依此类推。如果您使用了游标,只要返回了大量等于您定义的游标大小的文档,您就可以开始迭代返回的文档,因为其他文档将根据需要从服务器上的游标延迟加载。 (有点简化,但足以回答这个问题)。你要做的是明确地等待,直到扫描索引,找到文档,发送回你的应用程序并将其到达最后一个文档的最后一个字节。正如@wdberkeley(为10gen工作)正确地指出,这是一个非常糟糕的想法。

可能导致或加剧问题的原因

在重负荷下,可能会发生两件事。您的_id索引不再存在于RAM中的可能性更大,导致数千(如果不是数百万)从磁盘读取 - 这是。比索引保存在RAM中要快得多(几个数量级)。所以它不是你提到的代码片段,而是MongoDB的响应时间导致延迟。重负载下的另一个选择是您的磁盘IO太低或(更有可能)随机文件读取延迟太高。我假设您正在使用旋转磁盘加上没有足够的RAM来存放大小的数据库。

如何找到原因

  1. 尝试使用db.users.stats()查找索引大小。我很确定你的索引大小(合并)超过你的可用内存。
  2. 测量磁盘IO和延迟。如果您使用GNU / Linux操作系统,您可能想知道IOwait百分比有多高。较高的百分比表示您的磁盘延迟对于服务器上的负载来说太高。甚至可能是您达到了磁盘的IO限制。
  3. 在mongo shell上进行查询。如果它们很快,你可以非常确定你的toArray调用是导致问题的原因。
  4. 如何解决问题

    如果没有足够的RAM,可以放大或缩小。

    如果您的磁盘延迟或吞吐量太高,要么横向扩展,要么(在大多数情况下更好,更便宜)使用SSD来存储MongoDB的数据。

    使用游标对象迭代文档。在我能想到的几乎所有用例中,这是一个更好的解决方案。

答案 1 :(得分:0)

将MongoDB驱动程序升级到3.6.4将立即获取数据。  我们的收藏集中有大约200万份文档,而以前的版本大约需要3分钟的时间,但是升级到3.6.4后仅花费了5-7秒的时间。所以我觉得旧版本存在一些问题的mongoDB驱动程序。