2014-02-21 41 views
4

我正嘗試在GAE應用程序中對數據存儲區中存儲的數據執行一些數據處理。瓶頸點是查詢返回實體的吞吐量,我想知道如何提高查詢的性能。提高對大數據的ndb查詢吞吐量

我做的一般:

  • 一切任務隊列的工作,所以我們有足夠的時間(10分鐘期限)。
  • 我對ndb實體運行查詢以選擇需要處理的實體。
  • 當查詢返回結果時,我將批量的實體(比如1000)分組並將它們發送到另一個任務隊列以供進一步處理。
  • 存儲的數據將會很大(例如500K-1M個實體),並且有可能10分鐘截止日期不夠。因此,當任務達到任務隊列截止日期時,我產生了一項新任務。這意味着我需要一個ndb.Cursor以便從停止的地方繼續查詢。

問題是查詢返回實體的速度。我嘗試了幾種方法並觀察到以下性能(對於我的應用程序而言速度太慢):

在while循環中使用fetch_page()。

該代碼是直接的

while has_more and theres_more_time: 
entities, cursor, more = query.fetch_page(1000, ...) 
send_to_process_queue(entities) 
has_more = more and cursor 

利用該方法,它需要25-30秒來處理10K實體。粗略地說,這是每分鐘20K個實體。我試着改變頁面大小或前端實例的類;性能沒有任何差異。

並行分段數據並激發多個fetch_page_async()。

This approach is taken from here (approach C)

整體性能仍與上述相同。我嘗試了不同數量的段(從2到10),以便有2-10個並行的fetch_async()調用。在所有情況下,總體時間保持不變。調用的並行fetch_page_async()越多,每次完成所需的時間就越長。我也嘗試了20次並行讀取,情況變得更糟。更改頁面大小或前端實例類也沒有影響。

通過一次fetch()調用獲取所有內容。

現在,這是最合適的方法(如果不是不合適的話)的情況下可能會耗盡內存,再加上我沒有得到一個光標的情況下,我需要生成到另一個任務(其實我贏了甚至沒有能力這樣做,任務只會超過截止日期)。爲了看看它的表現如何,我發現了這個好奇心,我觀察到了最好的表現! 10K實體花費了8-10秒,這大約是每分鐘60K個實體。現在是約。比fetch_page()快3倍。我想知道爲什麼發生這種情況

在單個循環中使用query.iter()。

這和第一種方法一樣。這將使用查詢迭代器的底層生成器,另外我可以從迭代器中獲取遊標以防我需要產生新任務,所以它適合我。使用查詢迭代器,它在16-18秒內獲取了10K個實體,每分鐘36-40K個實體。迭代器比fetch_page快30%,但是fetch()要慢得多。

對於上述所有方法,我嘗試了F1和F4前端實例,沒有任何數據存儲性能差異。我也嘗試在查詢中更改batch_size參數,仍然沒有任何改變。第一個問題是爲什麼fetch(),fetch_page()和iter()的行爲如此不同以及如何使fetch_page()或iter()與fetch()同樣好?另一個關鍵問題是這些吞吐量(每分鐘20-60K實體,取決於api呼叫)是否是我們在GAE中可以做到的最好的。

我知道MapReduce API,但我認爲它不適合我。 AFAIK,MapReduce API不支持查詢,我不想掃描所有的數據存儲實體(這將是太昂貴和慢 - 查詢可能只返回幾個結果)。最後但並非最不重要的,我必須堅持GAE。訴諸另一個平臺對我來說不是一種選擇。所以問題的確是如何優化ndb查詢。

有什麼建議嗎?

+0

爲了您的處理,我沒有看到任何真正的理由使用fetch_page,只是使用fetch提供限制和遊標,您不需要倒退,或者知道它們可能是一些添加記錄(這是一個開銷fetch_page正在添加)。最終,這是在引擎蓋下使用的。 –

+0

我不知道我跟着你。如何從fetch()獲取光標?您可以限制提取結果,但返回的結果只是實體列表。在調用fetch()之後我沒有看到獲取光標的方法。也有偏移量參數,但根據文檔,這是不高效的。 – Christos

+0

對不起,我在想db不是ndb。 –

回答

0

新的實驗Data Processing功能(適用於MapReduce的AppEngine API)可能比較合適。它使用自動分片來執行多個並行工作進程,這可能會或可能不會幫助(如其他鏈接問題中的方法C)。

+0

AFAIK,MapReduce Api不適用於查詢。它掃描整個數據存儲,我想一直避免這種情況。查詢只能匹配幾條記錄,不需要掃描所有實體。 – Christos

0

您對「不需要掃描所有實體」的評論觸發了自定義索引可以幫助您查詢的想法。這可能需要模式更改以不常規的形式存儲數據。

從輸出的角度設計一個解決方案 - 最簡單的查詢是什麼產生了所需的結果,然後實體結構支持這樣的查詢,然後需要做什麼工作來創建和維護這樣的實體結構當前數據。

2

如果有人感興趣,我可以通過重新設計組件來顯着提高數據處理的吞吐量 - 建議我更改數據模型,但這是不可能的。

首先,我分割數據,然後在單獨的任務隊列中處理每個數據段。任務,而不是從單個任務調用多個fetch_page_async(如我在第一篇文章中所述)。最初,這些任務由GAE按順序使用一個Fx實例進行處理。爲了實現任務的並行化,我將組件移至特定的GAE模塊,並使用基本縮放比例,即可尋址的Bx實例。當我排隊每個數據段的任務時,我通過指定'target'選項明確指示哪個基本實例將處理每個任務。使用此設計,我能夠在4-5秒內(而不是40'-60'!)使用5個B4實例處理總共20.000個實體。

現在,由於Bx實例,這有額外的成本。我們必須微調我們需要的基本實例的類型和數量。

+0

不錯。我對你的問題感興趣,很高興你回答。 –