2016-11-16 85 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讀取。 –

相關問題