問題背景: 近期在重構公司內部一個重要的任務係統,由於原來的任務係統使用了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的?
初步的思考了一下,僅供參考:
個人認為題主提到的MongoDB陣列查詢和更新的效能問題,很可能是Schema設計上的問題。但題主並沒有給出具體的設計,所以我就提出幾個值得關注的要點僅供參考:
mongodb是一個內存型的資料庫,如果你的熱點資料都在記憶體上,它的效能會非常優異,而這很大程度取決與你的Schema設計。
PS:mongodb一直標榜的Schemaless優點誤導了許多人,其實這個比較想說明mongodb是動態的schema,而並不是不需要設計schema。
任務佇列可以考慮 rabbitmq 另外mongodb不應該這麼慢吧,沒加索引?或試試capped collection.