我正嘗試在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查詢。
有什麼建議嗎?
爲了您的處理,我沒有看到任何真正的理由使用fetch_page,只是使用fetch提供限制和遊標,您不需要倒退,或者知道它們可能是一些添加記錄(這是一個開銷fetch_page正在添加)。最終,這是在引擎蓋下使用的。 –
我不知道我跟着你。如何從fetch()獲取光標?您可以限制提取結果,但返回的結果只是實體列表。在調用fetch()之後我沒有看到獲取光標的方法。也有偏移量參數,但根據文檔,這是不高效的。 – Christos
對不起,我在想db不是ndb。 –