Go遊戲服務端框架從零搭建(一)— 架構設計

         五邑隱俠,本名關健昌,10年遊戲生涯,現隱居海邊。

  本教程以Go語言分區遊戲服務端框架搭建爲例。

  Go語言是Google開發的一種靜態強類型、編譯型、併發型、具有垃圾回收功能的編程語言。語法上近似C語言,支持接口、可通過struct包含另一個struct方式實現繼承等面向對象的概念。性能上媲美C/C++,相比C/C++更健壯,更易開發併發程序。我以前也寫C++服務端,接觸Go後,更傾向用Go做遊戲服務端開發。

  所謂分區遊戲,指遊戲將分爲很多個區,不同區之間玩家不能互動或只有少量互動。玩家進入遊戲需要選擇分區,進入指定分區進行遊戲,一個玩家可以同時在不同分區有角色。目前市面上大多中重度網絡遊戲都採用這種模式,分區遊戲適合不需要大DAU互動的遊戲,如卡牌、MMORPG、SLG等。從技術層面,分區屬於集羣擴容的一種手段;運營上,有利於分區精細運營,滾服運營已經是比較成熟的遊戲運營手段。相對分區遊戲,也存在不分區的社交遊戲,這類遊戲核心玩法是匹配對抗,例如COC。如果把分區遊戲的分區,映射爲該類遊戲的節點服,廣播服映射爲匹配服,對不分區遊戲的架構也就很好理解。

  本教程主要講分區遊戲服務端框架搭建。總體設計如下:

  分區遊戲,玩家先登錄遊戲,然後進入指定分區。所以首先要有一個登錄服務器,提供全局的登錄服務。登錄服務器的核心數據是玩家賬號,核心業務是對玩家進行登錄校驗,包括使用自有賬號系統、第三方賬號登錄。賬號數據需要落地長期存儲,所以在該服務器配套一個MySQL數據庫,用於保存玩家賬號信息。有一到多個登錄服務進程,進行遊戲登錄校驗。登錄服務是一個短連接服務,使用http協議,對外通過nginx提供統一訪問地址,對多個登錄服務進程做負載均衡。通常,登錄接口還會返回分區信息、玩家各分區角色簡要信息、客戶端最新版本號、配置版本、資源版本、公告等,這些信息可以通過gm服務(後面會介紹)動態更新,登錄服在響應請求時獲取並返回給客戶端。所以在登錄服務器會配套一個redis服務,用於這些數據的緩存。

  玩家登錄遊戲成功後,將進入選定遊戲分區。分區是一組服務進程。大部分遊戲分區都採用長連接通信,如果同時兼顧現在熱門的h5遊戲、微信小遊戲,考慮選用websocket做通信(以前使用socket)。考慮到遊戲中會有廣播的需求,廣播數據和分區遊戲數據都希望從同一個連接返回給客戶端,有必要提供一個統一的分區入口網關服,網關服進程對客戶端提供統一的分區地址和端口,對內做數據轉發。分區的邏輯業務可以集中放在一個遊戲服進程裏。以前一些遊戲,遊戲服在線數據會保存在進程內存裏,由於遊戲數據變化太頻繁,MySQL 頻繁讀寫性能不高,所以會隔一定時間才保存到MySQL。但分區內遊戲服是一個單點,一旦崩掉,遊戲服的內存數據就會丟失,回檔到上一次保存的時間。後來一些遊戲爲了減少這種風險,把在線數據保存到共享內存,再定時保存到MySQL。共享內存依賴系統和語言,目前發現Go沒有直接支持。再後來有了memcached和redis,部分遊戲選擇用這種緩存系統做緩存,遊戲服崩掉,數據還在緩存裏不會丟失,可以快速啓動遊戲服恢復服務。我選用redis作爲緩存,緩存活躍玩家數據。隔一定時間,把變化數據保存到MySQL。redis數據主要使用key-value方式保存數據,每次業務處理都需要讀取、解析,再使用。對業務開發不是很友好。遊戲服進程內存還是會保存在線玩家數據,玩家進入分區時從redis讀取到遊戲服內存,redis不命中則發佈消息給數據服進行數據預熱,預熱成功後從redis讀取。後面的請求可以直接通過內存數據做業務判斷、處理,更改數據以事務方式保存到redis,成功後響應給客戶端。這樣內存數據跟redis數據一致,而且可以把玩家數據拆成更細的單元,減少跟redis間的通信。玩家下線後清除遊戲服內存數據。所以分區內配套一個redis、一個MySQL。爲了建立定時保存數據這個機制,且不會因遊戲服崩潰而受影響,配備一個功能很簡單的數據服,通過redis的發佈訂閱機制、消息隊列,負責數據的定時落地固化、玩家註冊、數據預熱。

  前面提到廣播服,廣播服顧名思義主要負責廣播,例如跑馬燈廣播、世界聊天、世界boss。廣播服通過各個分區的網關服將數據廣播給玩家,因此廣播服將連接各個分區網關。廣播任務通過消息隊列進行緩存,這樣每個分區的廣播操作在寫到隊列後就可以響應客戶端。消息隊列採用redis實現。廣播服是一個全局的服務,爲了避免單點風險,可以做成主從,通過redis的訂閱發佈機制,啓動時訂閱redis,如果一定時間沒有收到發佈消息,認爲主服務不存在,切換爲主服務,取消消息訂閱,連接各分區網關,定時向redis發佈消息報活。

  除了業務相關的服務,需要對整個服務體系提供管理。例如開服、停服、更新配置/資源版本、發郵件、發公告、發放道具、踢人等。提供一個全局的gm服,各分區服務啓動後,遊戲服進程連接到gm服並保持心跳,以通知gm服開/停服。gm服將這些變更信息更新到登錄服的redis,這樣玩家登錄遊戲就知道各個服的狀態。gm服還可以通過向redis發消息通知登錄服進行封號等操作。由於各個遊戲服都連接到gm服,這樣就可以對各個分區發gm命令。gm服可以通過向廣播服的消息隊列寫消息發全員廣播。gm服的功能由運營人員進行操作,所以需要提供http服務,方便在網頁上訪問。gm服有道具發放的功能,所以第三方支付回調可以通過gm服的http接口請求發貨。

  爲了給運營提供決策,還需要提供統計後臺,對遊戲數據日誌進行收集、統計。由於登錄服、各分區的遊戲服、gm服都會上報數據,數據來源廣,數據量大,需要做消息隊列。因此登錄服、遊戲服、gm服都通過redis的消息隊列進行上報。統計服從redis讀取消息,保存數據日誌到MySQL。因此需要配套一個redis、一個MySQL。統計服的功能由運營人員使用,需要提供http服務,方便在網頁上訪問。統計服的http接口還支持客戶端進行數據上報。

  爲了合併運營人員的頁面,gm服、統計服通過nginx提供統一的http地址。

  這樣就得到了如前面設計圖的整個服務框架。 

  本篇介紹到這裏,接下來會詳細介紹各個服務的實現。在此之前,下一篇先介紹一些通用的基礎機制設計和實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章