2016-11-16 87 views
1

我们有每天运行的计划作业,这个作业查找当天匹配的文档,并获取文档并进行最小的转换,并将其发送到下游处理队列。通常我们有一天要处理4百万个文件。我们的目标是在一小时内完成加工。我正在寻找关于最佳实践的建议,以便快速从MongoDB中读取400万份文档?Mongo DB读取4百万个文档

+0

是否有语言要求? –

+0

我们是一个java商店,使用java-mongo驱动程序。 –

+0

您对语言和/或驱动程序是否灵活? –

回答

1

MongoDB Async driver是低开销查询的第一站。有使用该网页上SingleResultCallback良好example

Block<Document> printDocumentBlock = new Block<Document>() { 
    @Override 
    public void apply(final Document document) { 
     System.out.println(document.toJson()); 
    } 
}; 
SingleResultCallback<Void> callbackWhenFinished = new SingleResultCallback<Void>() { 
    @Override 
    public void onResult(final Void result, final Throwable t) { 
     System.out.println("Operation Finished!"); 
    } 
}; 

collection.find().forEach(printDocumentBlock, callbackWhenFinished); 

在异步数据库驱动程序的通用模式,让结果进行处理,尽快为他们提供转嫁。使用OS级别的异步I/O将有助于降低CPU开销。这引发了下一个问题 - 如何获取数据。

没有看到您的工作细节,您可能希望将结果放入内存队列中,此时由另一个线程拾取,以便读者线程可以继续读取结果。 ArrayBlockingQueue可能是适当的。 putadd更合适,因为如果工作人员无法跟上(保持平衡),它将阻止读者线程。理想情况下,您不希望它备份,这是需要多个线程的地方。如果结果顺序很重要,请使用单个工作线程,否则使用ThreadPoolExecutor,将队列传递给构造函数。使用内存中的队列确实会在数据被读取时以某种方式被丢弃(即,如果您立即发送另一个查询以删除它们)并且读取器进程崩溃,则会造成数据丢失的可能性。

此时,要么在工作线程上执行'minimal transforms',要么在worker中对它们进行序列化,并将它们放到真正的队列中(例如RabbitMQ,ZeroMQ)。将它们放到一个真正的队列中,可以将工作细分为多个机器,并提供可选的持久性以允许恢复工作,这些队列具有很好的可伸缩性群集选项。那些机器可以将结果放入问题中提到的队列中(假设它具有容量)。

像这样的系统中的瓶颈是一台机器能够通过单个mongo查询的速度以及最终队列可以处理多少个结果。所有其他部分(MongoDB,队列,工作者机器数量)都可以单独扩展。通过在查询机器上尽可能少的工作并将该工作推到其他可以大大降低影响的机器上。这听起来像你的目标队列超出你的控制。

当试图找出瓶颈所在的位置时,测量至关重要。预先向您的应用程序添加metrics可以让您知道事情进展不顺利时需要改进哪些方面。

该设置可以构建一个漂亮的可扩展系统。我以前建了很多类似的系统。除此之外,您需要调查将您的数据转化为Apache Storm之类的内容。

+0

当然@亚历克斯感谢您的评论,我们使用相同的模式,使用阻塞队列'数据一旦出来'(实现我们使用骆驼赛达(http://camel.apache.org/seda.html),给出)我们考虑过Storm,并认为它是一种很好的技术,但是只在需要时才使用,因为它增加了主管/工作者的复杂性。)我们将尝试使用Mongo Async驱动程序mongo读取。 –

相关问题