搜尋

首頁  >  問答  >  主體

MongoDB + Redis 任務佇列效能瓶頸

問題背景: 近期在重構公司內部一個重要的任務係統,由於原來的任務係統使用了MongoDB來保存任務,客戶端從MongoDB來取,至於為什麼用MongoDB,是一個曆史問題,也是因為如果使用到MongoDB的數組查詢可以減少任務數量很多次,假設這樣的情況,一個md5需要針對N種情況做任務處理,如果用到MongoDB的數組,隻需要將一個md5作為一條任務,其中包含一個長度為N的待處理任務列表(隻有N個子任務都處理完後整個任務才算處理完畢),這樣整個任務係統的數量級就變為原來的 1/N。

細節描述: 1.當MongoDB的任務數量增多的時候,數組查詢相當的慢,任務數達到5K就已經不能容忍了。 2.任務處理每個md5對應的N個子任務必須要全部完成才從MongoDB中刪除 3.任務在超時後可以重置

改進方案如下: 由於原有代碼的耦合,不能完全拋棄MongoDB,所以決定加一個Redis緩存。一個md5對應的N個子任務分發到N個Redis隊列中(拆分子任務)。一個單獨的進程從MongoDB中向Redis中將任務同步,客戶端不再從MongoDB取任務。這樣做的好處是拋棄了原有的MongoDB的數組查詢,同步進程從MongoDB中取任務是按照任務的優先級偏移(已做索引)來取,所以速度比數組查詢要快。這樣客戶端向Redis的N個隊列中取子任務,把任務結果返回原來的MongoDB任務記錄中(根據md5返回子任務)。

改進過程遇到的問題: 由於客戶端向MongoDB返回時候會有一個update操作,如果N個子任務都完成,就將任務從MongoDB中刪除。這樣的一個問題就是,經過測試後發現MongoDB在高並發寫的情況下性能很低下,整個任務係統任務處理速度最大為200/s(16核, 16G, CentOS, 內核2.6.32-358.6.3.el6.x86_64),原因大致為在頻繁寫情況下,MongoDB的性能會由於鎖表操作急劇下降。

具體問題: (Think out of the Box)能否提出一個好的解決方案,能夠保存任務狀態(子任務狀態),速度至少超過MongoDB的?

迷茫迷茫2799 天前785

全部回覆(3)我來回復

  • 迷茫

    迷茫2017-04-22 08:58:16

    初步的思考了一下,僅供參考:

    1. 首先,提一下索引,相信這個你應該加了索引。
    2. 有個問題確認一下,mongodb最新版本中的鎖定粒度還是Database等級吧,不知道你用的哪個版本,還沒到鎖表(Collection)這個粒度,所以寫並發大的情況下比較糟糕,不過應該性能也不至於糟到像你描述的那樣啊?不解,建議考慮任務分庫的可能性?
    3. 能否考慮把子任務的狀態和主任務的狀態分開保存。子任務的狀態,可以放到redis,主任務只負責自己本身的狀態,讓每個主任務更新頻率降到1/N,可大幅減少mongodb中主任務表的壓力。
    4. 子任務完成或逾時後,可否考慮後台非同步單執行緒順序同步mongodb的主任務狀態?

    回覆
    0
  • 阿神

    阿神2017-04-22 08:58:16

    個人認為題主提到的MongoDB陣列查詢和更新的效能問題,很可能是Schema設計上的問題。但題主並沒有給出具體的設計,所以我就提出幾個值得關注的要點僅供參考:

    1. 索引,正如樓上所說,你應該已經為數組加上了索引。但值得注意的是,數組欄位的索引比普通欄位的索引體積要大得多(取決於數組的大小,數組越大,索引所佔的空間越大)。這樣就可能會導致一個問題:索引並沒有(完全)在記憶體裡! 後果是,每次查詢都需要涉及額外的IO操作,效能會急劇下降。
    2. 查詢傳回文檔的大小。如果每次回傳查詢的文件資料量較大,而且客戶端與mongodb並不處於同一機器上,那就會增加了網路傳輸所需的時間(不要小看這點時間),所以盡可能只回傳所需要的字段。
    3. update-in-place. 由於schemaless的特性,mongodb會為每筆文件記錄預留一些空間給增加額外的欄位或資料時使用,提高update的效能。但如果你文件的大小頻繁地擴展(增加字段,增加數組長度等),那就會導致寫的性能問題:mongodb需要把增長了的文檔移動(move)到別的地方。 (相當於從硬碟的一個位置移動另一個更空閒的位置)這時候的效能會大大下降。

    mongodb是一個內存型的資料庫,如果你的熱點資料都在記憶體上,它的效能會非常優異,而這很大程度取決與你的Schema設計。

    PS:mongodb一直標榜的Schemaless優點誤導了許多人,其實這個比較想說明mongodb是動態的schema,而並不是不需要設計schema。

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-22 08:58:16

    任務佇列可以考慮 rabbitmq 另外mongodb不應該這麼慢吧,沒加索引?或試試capped collection.

    回覆
    0
  • 取消回覆