1. 程式人生 > >rpc服務在遊戲中的簡單運用

rpc服務在遊戲中的簡單運用

我們最開始做的遊戲框架,多數都是client—>server—>db的模式,但是隨著玩家數量的增加,一個server程序就會扛不住,需要多個程序服務於多個玩家。但是給定了不同程序的玩家,有可能需要互動,這就導致了client與server端的連線,有可能是o(1),但也可能是o(n)連線,o(n)的擴充套件性非常差,不容易維護,因此可以剔除了。但是如果只保持o(1),那必然要引入新的抽象服務,閘道器也就登場了。下圖是一個簡單的閘道器部署架構:

 

閘道器的引入,有哪些改變呢?
  • 內外網解耦,在保持客外網客戶端不變的情況下,可以通過這個中間層調整內網服務的實現
  • 規範化,由於請求是閘道器統一接受和分發的,會直接促使客戶端在傳送和接受請求時規範化
  • 安全,由於閘道器具有收口作用,所有的安全問題都可以在這裡解決,保護內網,比如反爬,認證等功能
  • 限流熔斷,在閘道器上實現限流,避免內網被突發流量壓垮
  • 統一的監控告警平臺

 

有了閘道器後,開始在下游增加業務邏輯,可能我們會把所有的業務都耦合成一個service,比如聊天掛了,派系掛了,場景掛了,都可能會對有戲本身產生影響;基於此,不得不考慮拆分程序,之前的遊戲service服務,可能會被拆分為多個服務,但是對於大多數的遊戲開發人員來說,基於服務的開發,比基於程序的開發,也難的多,如果不是領導推進,也不會有人願意把聊天做成一個單獨的服務。 對於遊戲來說,服務拆分最最極端的情況,就是一個訊息cmd對應了一個service,但是這種情況會導致service越來越多,無法維護的程度,實際上游戲拆分也確實沒有必要。不過服務service越來越多,某個service甚至處於記憶體,cpu瓶頸的狀態,應該如何解決呢?這時候rpc的服務治理派上了用場。我們對上面的圖示做下改動:

 

 

game-rpc的引入,解決了哪些問題呢?
  • 開發人員不再需要關注內部通訊機制,減少專案開發時間,降低成本
  • 強大的叢集容錯,負載均衡能力等,保證每次呼叫都能路由到合適的節點

 

service與service做成了叢集,每個service啟動後,往zk或nacos註冊中心註冊自己的url。gateway在啟動後,訂閱zk註冊中心的service列表,依託於rpc本身強大的叢集,負載等功能,可以自動實現service的切換。 在針對rpg等長連線遊戲型別時,玩家在場景中的移動都需要同步,廣播給周圍的玩家,但是rpc是單通道的,不能回傳,這應該如何處理呢? 有借於此,game-rpc增加了全雙工的概念,不僅僅是client對service的請求,同時service也可以根據uniqueId,進行主動推送。於是上面的流程圖變成了下面這樣:  
  一切看上去都很完美,似乎沒有問題了,然而新的問題隨之出現。 我們知道,優秀的架構體系中,單點問題是不能容忍的,很不幸,我們的gateway,就出現了單點。隨著玩家數量的增加,整個服務都會處於不可用的狀態。於是閘道器需要拆成叢集的模式,新的架構圖顯示如下:     閘道器拆分後,gate1和gate2的玩家是兩個tcp長連狀態的服務,無法互動,這應該怎麼辦? 我們參照了現行市面上比較常用的tcp閘道器做法,訊息下行通知的解決方案,目前框架支援了兩種方式:
  • MQ廣播機制,當某臺網關伺服器收到廣播訊息後,MQ通知給叢集內的所有gate server,每個gate在收到訊息後,判斷要推送端的訊息是否是當前gate所持有的會話,如果在當前服務,則進行推送,否則拋棄
   
  • redis session共享,針對MQ的廣播機制,如果以後遊戲火爆,同時有百萬玩家線上,那麼gate叢集裡的機器,可能會達到上百臺不等,如果每個訊息都需要MQ廣播,有可能會導致訊號風暴,於是我們調整了最後一種解決方案。玩家在登入閘道器,認證成功後,把玩家id作為key,當前連線的閘道器uniqueId作為value,儲存到redis叢集中。閘道器隨後把訊息路由到具體某個service,service從redis叢集裡獲取到需要廣播的玩家對應的gate服務,service通過rpc訊息下行,直接推送到具體的gate,再由gate轉發到client
    說明:這種架構,更適用於全區全服型別的遊戲。目前我們已經有多款線上遊戲使用。
更多交流,也歡迎您關注我的微信公眾號: