現象:mysql
同事負責的項目轉到我部門,整理服務過程當中發現了隊列的積壓問題。redis
爲了搞清楚積壓的嚴重程度, 對隊列任務數每分鐘進行一次採樣,生成一個走勢圖, 隊列積壓狀況一目瞭然,很是嚴重。 sql
分析:mongodb
聽了同事對系統的介紹,猜想是mongo性能影響了處理效率,因而針對mongo進行分析shell
1. 使用mongotop /usr/local/mongodb/bin/mongotop --host 127.0.0.1:10000數據庫
odds_easy.basic_odds表的操做一直排第一,寫操做佔大部分時間json
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的錯誤選擇形成了寫熱點,將寫集中到了同一個分區,進一步加重了寫的阻塞
【能夠看到前期合理的架構設計是多麼的重要】
分兩個階段:
目的
系統中加入redis作熱數據緩存, zookeeper/etcd做爲配置服務中心以及熱數據導入的流程控制中心
架構圖
update_betting_offer隊列的GermanWorker啓動新增流程
在german註冊一個任務名稱,名字爲第一步中的節點內容
"本機IP進程號_update_setting"任務處理流程:
定時任務流程:
初賠結構, key值: 「event_id:betting_id:start」 , value值爲hash類型,hash_key:provider_id;hash_value:跟mongo中的結構一致,json格式;如{"i":{"t0":{"h":4.27,"d":3.24,"a":1.88},"t1":0.9305,"t2":{"h":0.2179,"d":0.2872,"a":0.4949},"t3":{"h":0.93,"d":0.93,"a":0.93}},"s":1,"t":"2017-04-03 13:39:28","b":0,'p':744 }
終賠結構,key值:"event_id:betting_id:end" value值同初賠
平均結構,key值:"event_id:betting_id:avg" value值同初賠
變化過程,key值:"event_id:betting_id:provider_id:boundary", value值爲sorted set, member爲賠率信息,跟mongo中的結構一致,json格式;如{"i":{"t0":{"h":4.27,"d":3.24,"a":1.88},"t1":0.9305,"t2":{"h":0.2179,"d":0.2872,"a":0.4949},"t3":{"h":0.93,"d":0.93,"a":0.93}},"s":1,"t":"2017-04-03 13:39:28","b":0,'p':744 }。 score爲時間,如20170403133928
若是按照上面的結構進行存儲, 進行了大概的預估。
對2789場比賽進行了歐賠統計,平均一場比賽2006個初賠,2006個終賠;583個boudary值,每一個boundary結構中存23個賠率變化;這樣計算一場比賽須要大概 5.5m, 盤口數據大概爲歐賠的一半。總8M
若是放入全部未開賽的比賽,大概1個半月的比賽,1w場比賽,所需內存80G,這個量太大了。
因此只放入熱數據,2天內未開賽的比賽,保存3天,3天比賽450場左右。 須要 3.6G
----------------後續:第一階段優化完後高峯期最高120左右