有哪些開源?html
KBEngine《暗黑戰神》 git
最後一戰github
pomelo redis
skynet編程
muduo緩存
GoWorld服務器
服務引擎要實現什麼?網絡
核心兩個問題:消息的pipeline與遊戲世界狀態維護。多線程
網絡:框架
定義client到server、server到client、server到server的消息流。
咱們看手邊工具,socket(最好是單線程的,而且跟IO無關,可參考衆多網絡庫)。
首先解決的一點就是,將傳輸層的協議轉換爲應用層的消息協議。
要解決的第二個問題是,爲應用層創建IO模型。
要解決的第三個問題是,封裝具體的鏈接細節。
多線程技術或多進程技術
信號
定時器
服務\實體(抽象成粒度最小):
能夠簡單理解爲一組方法集合。服務是分佈式遊戲服務端中的最小實體,一個服務提供了一組肯定的、可供調用的方法。
skynet中,一個skynet_context惟一對應一個服務,而一個skynet節點對應一組服務;傳統MMO中,一個進程對應一組服務,可是很難在其中找到「一個」服務的劃分界限。
服務的概念就是爲了提出一種與物理容器無關的抽象。服務能夠以某個進程爲容器,也能夠以某個線程爲容器。能夠像skynet同樣以一個luaState爲容器,也能夠像Erlang遊戲服務端那樣以一個actor爲容器。而一個容器也能夠提供多種服務。
服務中的數據定位
遊戲世界的狀態能夠簡單分爲兩個部分,一部分是須要存檔的,好比玩家數據;一部分是不須要存檔的,好比場景狀態。
對於訪問較頻繁的部分,好比場景狀態,會維護成純內存數據;對於訪問較不頻繁的部分,好比玩家存檔,就能夠考慮維護在第三方。這個第三方,就是數據服務。
數據服務與以前所提到的場景服務、IM服務等都屬於應用層的概念。數據服務一般也會依賴於一種基礎設施抽象,那就是緩存。
咱們能夠將服務狀態存放在外部設施中,好比數據服務。
無狀態服務
將狀態存放在外部設施的服務就是無狀態服務。而與之對應的,場景服務這種狀態須要在進程內維護的就是有狀態服務。無狀態遊戲客戶端意味着網絡通訊的成本跟內存數據訪問的成本同樣低——這固然是不可能實現的。遊戲中能夠拆分爲無狀態服務的業務需求其實有不少,基本上全部服務間交互需求均可以實現爲無狀態服務。好比切場景服務,由於切場景的請求是有限的,對時延的要求也不會特別高,同理的還有分配房間服務;或者是面向客戶端的IM服務、拍賣行服務等等。
遊戲服務端中的Message Queue
面對這種需求,咱們須要一種消息隊列中間件。
生產者消費者一直都是一種比較經典的解耦模型,而消息隊列就是基於這種模型構建的。每一個skynet節點本質上就是一個高度精簡的消息隊列,爲寄宿的每一個服務維護一個私有隊列,對全局隊列中的消息dispatch,驅動寄宿服務。
而我但願的是更純粹的消息隊列中間件
就咱們的遊戲服務端需求來講,zk能夠用來選leader,還能夠用來維護dbClient的配置數據——dbClient直接去找zk要數據就好了。
簡單介紹下如何基於zk實現leader election。zk提供了一個相似於os文件系統的目錄結構,目錄結構上的每一個節點都有類型的概念同時能夠存儲一些數據。zk還提供了一次性觸發的watch機制。leader election就是基於這幾點概念實現的。
假設有某個目錄節點/election,watcher1啓動的時候在這個節點下面建立一個子節點,節點類型是臨時順序節點,也就是說這個節點會隨建立者掛掉而掛掉,順序的意思就是會在節點的名字後面加個數字後綴,惟一標識這個節點在/election的子節點中的id。
一個簡單的方案是咱們能夠每一個watcher都watch /election的全部子節點,而後看本身的id是不是最小的,若是是就說明本身是leader,而後告訴應用層本身是leader,讓應用層進行後續操做就好了。可是這樣會產生驚羣效應,由於一個子節點刪除,每一個watcher都會收到通知,可是至多一個watcher會從follower變爲leader。
優化一些的方案是每一個節點都關注比本身小一個排位的節點。這樣若是id最小的節點掛掉以後,id次小的節點會收到通知而後瞭解到本身成爲了leader,避免了驚羣效應。
一些思想
操做系統依賴的IO複用,線程編程,內存管理, 腳本系統。分佈式服務實現
實現actor框架的思路,有Lua/C的交互以及協程實現的思路,字節碼編譯加載,分佈式服務實現,集羣間通訊,超時檢查,讀寫第三方開源服務(redis,mongo)。
entity
參考: