2013-03-01 90 views
24

這是我的官方第一個問題,我歡迎對我的帖子的任何/所有批評,以便我可以學習如何成爲一個更好的SO公民。比較MongoDB和RethinkDB Bulk插入性能

我正在審覈非關係型數據庫管理系統,用於存儲可能使用各自的Python客戶端庫的大型電子郵件退出列表,傾向於MongoDB或RethinkDB。我的應用程序的難點在於批量插入性能,所以我已經設置了兩個Python腳本,以便將5,000個批量的20,000條記錄插入到MongoDB和RethinkDB集合中。

MongoDB的Python腳本mongo_insert_test.py:

NUM_LINES = 20000 
BATCH_SIZE = 5000 

def insert_records(): 
    collection = mongo.recips 
    i = 0 
    batch_counter = 0 
    batch = [] 
    while i <= NUM_LINES: 
     i += 1 
     recip = { 
      'address': "test%[email protected]%d.com" % (i, i) 
     } 
     if batch_counter <= BATCH_SIZE: 
      batch.append(recip) 
      batch_counter += 1 
     if (batch_counter == BATCH_SIZE) or i == NUM_LINES: 
      collection.insert(batch) 
      batch_counter = 0 
      batch = [] 

if __name__ == '__main__': 
    insert_records() 

幾乎相同的RethinkDB python腳本rethink_insert_test.py:

NUM_LINES = 20000 
BATCH_SIZE = 5000 

def insert_records(): 
    i = 0 
    batch_counter = 0 
    batch = [] 
    while i <= NUM_LINES: 
     i += 1 
     recip = { 
      'address': "test%[email protected]%d.com" % (i, i) 
     } 
     if batch_counter <= BATCH_SIZE: 
      batch.append(recip) 
      batch_counter += 1 
     if (batch_counter == BATCH_SIZE) or i == NUM_LINES: 
      r.table('recip').insert(batch).run() 
      batch_counter = 0 
      batch = [] 

if __name__ == '__main__': 
    insert_records() 

在我的開發環境,MongoDB的腳本插入20,000條記錄中下秒:

$ time python mongo_insert_test.py 
real 0m0.618s 
user 0m0.400s 
sys  0m0.032s 

在相同的環境中,R ethinkDB腳本執行慢得多,在過了2分鐘插入20,000條記錄:

$ time python rethink_insert_test.py 
real 2m2.502s 
user 0m3.000s 
sys  0m0.052s 

我缺少的東西在這裏龐大對於這兩個數據庫管理系統是如何工作的?爲什麼RethinkDB在這個測試中表現得如此糟糕?

我的開發機器有大約1.2GB的可用內存用於這些測試。

+5

標題說明了一切;)http://www.rethinkdb.com/blog/the-benchmark-youre-reading-is-probably-wrong/ – 2013-03-21 16:44:14

+0

@FabianoPS,我沒有真正瞄準任何科學的東西;只是想知道爲什麼要花更多的時間在Rethink上做和MongoDB一樣的操作。我不認爲網絡/磁盤延遲扮演了很多角色(如果有的話)。反思已經發布了一個更新,以一種有希望的有意義的(非膚淺的)方式來解決這個問題。 – njyunis 2013-03-22 17:26:22

+0

嗨@njyunis嗨@njyunis,這篇文章在它的核心信息中有很多有趣的地方:有很多解釋速度的寫作,這是一個評論而不是答案 – 2013-03-22 23:46:03

回答

46

RethinkDB當前通過在服務器上一次執行一次插入來實現批量插入。由於Rethink會將每條記錄刷新到磁盤(因爲它的設計首先考慮到安全性),所以這對工作負載的影響非常糟糕。

我們正在做兩件事情來解決這個問題:

  1. 批量插入將通過批量插入算法實現在服務器上,以避免在同一時間做一個插件。
  2. 我們將爲您提供放鬆持久性約束的選項,以允許緩存內存吸收高吞吐量插入(如果您願意)(以換取不經常同步到磁盤)。

這將在4-12周內完全修復(如果您需要這個儘快,請隨時向我發送電子郵件至[email protected],我會看看我們是否可以重新排列優先順序)。

下面是相關GitHub的問題:

https://github.com/rethinkdb/rethinkdb/issues/207

https://github.com/rethinkdb/rethinkdb/issues/314

希望這有助於。如果你需要幫助,請不要猶豫,給我們打電話。

+0

謝謝@coffeemug,這回答我的問題。我會密切關注github,所以我知道什麼時候解決了這個問題,因爲我很高興給Rethink一個嘗試。 – njyunis 2013-03-01 14:50:04

+4

@njyunis:1.5最近用更快的批量插入:http://rethinkdb.com/blog/1.5-release/。 – 2013-05-27 07:08:47

6

撇開什麼coffemug發佈:

  1. 取決於你使用的是什麼驅動程序版本,以及如何配置連接到MongoDB的,這些刀片甚至可能不被服務器確認。如果您使用的是最新版本的Python驅動程序,那麼這些操作只是在等待來自服務器的收據確認(這並不意味着數據已經寫入內存)。對於我所指的更多細節,請查看Mongodb write concern setting

  2. 通過並行化插入,您可以在Rethinkdb的情況下加快速度。基本上如果你運行多個進程/線程,你會看到速度提升。在Mongo的情況下,由於涉及到鎖,並行性將無濟於事。

也就是說,RethinkDB可以提高寫入速度。 PS:我正在爲重新思考工作,但上述觀點是基於我對兩個系統的公正知識。

+0

pymongo的並行性也應該有所改善,因爲電線上的時間會減少阻塞。 – Ross 2013-03-01 09:59:49

+1

我要更新我的mongo測試腳本來使用MongoClient來解決這個問題。當我有機會這樣做時,我會編輯我的帖子。 – njyunis 2013-03-01 14:51:39

4

Pymongo開發人員在這裏 - 以防萬一你不這樣做,請確保你使用最新的pymongo版本和MongoClientMongoRepicaSetClient所以你的寫道是承認,而不是火和忘記。正如@Alex所說,他們很可能會成爲你需要的東西。

我會有的其他考慮因素是:這是數據庫的主要用例還是核心痛點?在作出決定之前,您可能需要考慮其他數據模式,查詢數據,易用性和可維護性。

+1

是的,我意識到在我做了測試後,我使用了一個相當過時的mongo客戶端;感謝您指出了這一點。我將Postgres數據庫用於一般的Django關係數據庫,而nosql用於電子郵件列表存儲,導入(批量插入)和清理(某種map/reduce比較列表)是nosql數據庫的兩個主要用例。 – njyunis 2013-03-01 14:45:39

0

請原諒這個比喻 - 但它使我的觀點清晰可見。

它不需要太多的時間來鎖定有價值的東西在安全,但做它成千上萬的意志。如果您發佈到銀行的保險庫,請考慮在您的銀行旅程中您的寶貴時間不夠安全的時間;該包裹可能會與其他許多包裹 - 從志同道合的存款人堆起來。有人會打開你的包裹,然後把它與其他東西堆放在一個安全的保險庫裏。

這就是常規提交數據到磁盤,以及批量或懶洋洋地將數據寫入磁盤的區別。這是在更高的數據完整性和改進的寫入性能之間取捨的結果。如果數據丟失並不重要,那麼可以不太頻繁地同步到磁盤,批量或懶惰地寫入更新是完全可以接受的。做出錯誤的選擇會讓你陷入一天,所以明智地選擇!