五邑隱俠,本名關健昌,10年遊戲生涯,現隱居海邊。
本教程以Go語言分割槽遊戲服務端框架搭建為例。
Go語言是Google開發的一種靜態強型別、編譯型、併發型、具有垃圾回收功能的程式語言。語法上近似C語言,支援介面、可通過struct包含另一個struct方式實現繼承等物件導向的概念。效能上媲美C/C++,相比C/C++更健壯,更易開發併發程式。我以前也寫C++服務端,接觸Go後,更傾向用Go做遊戲服務端開發。
分割槽遊戲,指遊戲將分為很多個區,不同區之間玩家不能互動或只有少量互動。玩家需要選擇分割槽進入指定分割槽開始遊戲,一個玩家可以同時在不同分割槽有角色。目前市面上大多中重度網路遊戲都採用這種模式,分割槽遊戲適合不需要大DAU互動的遊戲,如卡牌、MMORPG、SLG等。從技術層面,分割槽屬於叢集擴容的一種手段;運營上,有利於分割槽精細運營,滾服運營已經是比較成熟的遊戲運營手段。分割槽的基礎上,可以按相鄰分割槽編號設定組服務,例如10個分割槽一組設定組服務,用於跨分割槽的玩法。相對分割槽遊戲,也存在不分割槽的社交遊戲,這類遊戲核心玩法是匹配對抗競技,例如COC。簡單的匹配競技遊戲可以把分割槽遊戲的分割槽改為節點服務組,把組服務拆分成組匹配服務和多個競技服務,匹配服務只做簡單的報名和匹配,匹配成功後把玩家分配到指定的競技服務,並在裡面分配房間開始遊戲。
搭建分割槽遊戲服務端框架,首先建立一個服務註冊發現機制。我們以中心服作為機制的核心,提供服務註冊,以及服務資訊廣播。作為遊戲主體,分割槽是註冊的物件。分割槽啟動成功後,連線中心服,並註冊分割槽。這樣中心服知道所有分割槽的基本資訊和狀態。由於所有分割槽都連線中心服,中心服還有轉發、廣播的功能。分割槽註冊後,有哪些服務需要發現分割槽、關注分割槽的狀態變化?對於玩家,登入後要知道有哪些分割槽以及狀態情況。所以登入服需要發現分割槽。玩家通過登入返回知道分割槽情況,選擇分割槽進入遊戲。而玩家是通過閘道器連線分割槽的,所以閘道器需要發現分割槽。分割槽註冊後,需要切換狀態來支援開服測試、開服、維護。一般會搭建一個管理服,運營人員可以通過管理服發指令給分割槽更改狀態。所以管理服也需要發現分割槽。這樣得到第一個框架模型如下:
按照這個模型,先啟動中心服等待其他服務註冊。然後分別啟動管理服、登入服、閘道器,這些服務註冊到中心服。新開一個分割槽就啟動該分割槽服務,分割槽狀態為未開服。分割槽啟動成功後註冊到中心服,中心服通知管理服該分割槽啟動成功,狀態為未開服。管理服通過中心服轉發指令給該分割槽,更改狀態為開服測試。該分割槽把狀態更改發給中心服通知狀態變更。中心服通知管理服、登入服、閘道器該分割槽狀態變化。閘道器連線該分割槽的服務。這時候測試賬號可以登入進入該分割槽開始測試。測試通過後同理管理服可以發指令更改該分割槽狀態為正常正式開服。當分割槽需要維護時,管理服發指令給該分割槽更改狀態為維護,閘道器收到中心服廣播後,斷開與該分割槽服務的連線,5分鐘後該分割槽的服務可以關閉進入維護。這樣一個整體流程算是跑通了。
接下來看看分割槽的服務怎樣劃分。先看一個簡單的情況。分割槽有一個主服務,負責註冊到中心服、處理玩家的基本請求,包括分割槽登入、玩家基本資訊操作、養成等業務。這些業務都需要頻繁修改玩家資料,應避免直接運算元據庫,因此使用redis做快取,主服務直接操作redis上的資料。redis資料要有一個落地的機制避免redis崩潰或資料過期後資料丟失。這裡選用mysql做固化資料庫,玩家的遊戲資料會從redis固化到mysql。對於redis上資料已過期的玩家再次登入,還需要把資料從mysql載入到redis。所以這裡增加一個資料服,負責資料的預熱和落地。一個基本的流程,玩家進入分割槽,主服務處理請求,從redis獲取玩家資料,redis上不存在該玩家資料,主服務通過redis釋出訊息給資料服預熱該玩家資料,資料服查詢mysql,如果mysql沒有該玩家資料,資料服往mysql新加一條玩家資料註冊個新玩家,資料服把玩家mysql的資料新增到redis,資料服釋出訊息通知主服務該玩家資料已準備好,主服務繼續從redis獲取該玩家資料,返回給客戶端。這樣分割槽的基本流程也能跑通。
除了基本流程,分割槽可能需要廣播訊息,例如世界聊天、系統公告。在分割槽搭建一個廣播服,在redis裡維護一個廣播佇列,主服務往廣播佇列裡新增廣播訊息,廣播服從廣播佇列裡拿訊息進行廣播。對於MMORPG,還需要有場景服管理各個遊戲地圖,回合制的卡牌、MMORPG遊戲需要有單獨戰鬥服進行戰鬥的預演。如果有跨服玩法,還需要有組服務,相鄰幾個分割槽共用一個組服務。這樣得到的分割槽服務模型如下:
這樣一個基本的遊戲服務端框架輪廓就出來了。接下來需要封裝一些公共基礎功能,以便快速搭建各個服務