現象: 同事負責的項目轉到我的頭上,整理服務過程中發現了隊列的積壓問題。 為了搞清楚積壓的嚴重程度, 對隊列任務數每分鐘進行一次採樣,生成一個走勢圖, 隊列積壓情況一目瞭然,非常嚴重。 分析: 聽了同事對系統的介紹,猜測是mongo性能影響了處理效率,於是針對mongo進行分析 1. 使用mongo ...
現象:
同事負責的項目轉到我的頭上,整理服務過程中發現了隊列的積壓問題。
為了搞清楚積壓的嚴重程度, 對隊列任務數每分鐘進行一次採樣,生成一個走勢圖, 隊列積壓情況一目瞭然,非常嚴重。
分析:
聽了同事對系統的介紹,猜測是mongo性能影響了處理效率,於是針對mongo進行分析
1. 使用mongotop /usr/local/mongodb/bin/mongotop --host 127.0.0.1:10000
odds_easy.basic_odds表的操作一直排第一,寫操作占大部分時間
2. 看mongo shard日誌
大量超過1s的操作,集中在odds_easy.basic_odds寫操作, 看日誌lock數量很多
查詢某一個文檔的更新,在同一秒中居然有15個更新操作,這樣的操作產生什麼樣的結果: 大量的寫鎖,並且影響讀;而且還是最影響性能的數組的$push, $set操作
看看文檔的結構,數組的數量之大,而且裡面還是對象嵌套; 對這樣一個文檔不停的更新, 性能可想而知
看看 db.serverStats()的lock情況
看看odds_easy的db.basic_odds.stats()情況,大量的更新衝突
3. 看看sharding情況
使用腳本,查看sharding情況,重定向到文件中查看。
sql='db.printShardingStatus({verbose:true})'
echo $sql|/usr/local/mongodb/bin/mongo --host 192.168.1.48:30000 admin --shell
basic_odds的sharding信息:
shard key: { "event_id" : 1, "betting_type_id" : 1 } event_id為mysql自增欄位,betting_type_id為玩法id(意味著幾個固定的值,區別度不大)
shard 分佈情況, 從圖裡面可以看到mongo主要根據event_id這個自增欄位的範圍進行數據拆分, 意味著相鄰比賽的數據大概率會被分配到同一個shard分區上(這就是為什麼01機器上的日誌大小遠大於其他機器的原因吧,目前的數據都集中在shard1上)
下圖為資料庫讀寫情況, 更新操作是查詢操作的4倍。 對一個寫多讀少的資料庫, 本該將寫操作分佈到不同的分區上,結果由於sharding key的錯誤選擇造成了寫熱點,將寫集中到了同一個分區,進一步加劇了寫的阻塞
結論
- 文檔結構不合理,數組過大、更新過於頻繁,特別是對同一文檔。 對數組頻繁的更新操作是mongo最不推薦的,不僅影響本機的性能,還影響oplog的數據同步
- sharding key不合理造成了寫熱點, 在第一點不合理的基礎上,更加劇了性能的急劇下降, 還會造成頻繁的mongo數據遷移
(由於odds_easy.basic_odds的更新量大,目前問題在這個表上,但是其他表也有同樣的問題)
【可以看到前期合理的架構設計是多麼的重要】
解決思路
- 減少同一時刻對同一文檔的更新操作,將一定時間內的多次更新改為一次更新。
- 將更新最頻繁的process欄位從文檔中移出,寫到新的表中。 在新表中,同一event_id,betting_type_id, 賠率公司的變化在同一條記錄中
- 文檔結構中加入時間欄位,方便數據遷移,定期將歷史數據進行遷移,進行冷熱數據分離
- 修改sharding key為hash或者其他欄位,將寫操作分佈到不同的分區上
解決方案
分兩個階段:
第一階段 結構優化
- odds_easy庫中basic_odds, main_odds不再存儲最近10條的變化,去掉process欄位。
- 數據直接 mongo push到odds_change中對應的記錄rows欄位中
- 單獨提供介面,數據變化從odds_change中讀取, 使用 mongo的$slice讀出最近n條信息,然後程式排序截取即可
- odds_easy庫和odds_change庫中的表都使用 event_id 作 hash sharding key
- odds_easy, odds_change, odds_bet007, odds_betbrain_bb, odds_betbrain_v5, odds_txodds這些庫中的記錄都加入match_time欄位。 新增的記錄直接加入;歷史的記錄補全
第二階段 冷熱分離
目的
- 解決積壓問題
- 提高訪問速度
- 防止用戶對大量歷史的訪問從而影響熱數據的訪問。(可以在配置中加入開關, 出現問題時關閉歷史數據的訪問)
系統中加入redis做熱數據緩存, zookeeper/etcd作為配置服務中心以及熱數據導入的流程式控制制中心