五邑隱俠,本名關健昌,10年遊戲生涯,現隱居海邊。nginx
本教程以Go語言分區遊戲服務端框架搭建爲例。web
Go語言是Google開發的一種靜態強類型、編譯型、併發型、具備垃圾回收功能的編程語言。語法上近似C語言,支持接口、可經過struct包含另外一個struct方式實現繼承等面向對象的概念。性能上媲美C/C++,相比C/C++更健壯,更易開發併發程序。我之前也寫C++服務端,接觸Go後,更傾向用Go作遊戲服務端開發。redis
所謂分區遊戲,指遊戲將分爲不少個區,不一樣區之間玩家不能互動或只有少許互動。玩家進入遊戲須要選擇分區,進入指定分區進行遊戲,一個玩家能夠同時在不一樣分區有角色。目前市面上大多中重度網絡遊戲都採用這種模式,分區遊戲適合不須要大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接口請求發貨。websocket
爲了給運營提供決策,還須要提供統計後臺,對遊戲數據日誌進行收集、統計。因爲登陸服、各分區的遊戲服、gm服都會上報數據,數據來源廣,數據量大,須要作消息隊列。所以登陸服、遊戲服、gm服都經過redis的消息隊列進行上報。統計服從redis讀取消息,保存數據日誌到MySQL。所以須要配套一個redis、一個MySQL。統計服的功能由運營人員使用,須要提供http服務,方便在網頁上訪問。統計服的http接口還支持客戶端進行數據上報。網絡
爲了合併運營人員的頁面,gm服、統計服經過nginx提供統一的http地址。
這樣就獲得瞭如前面設計圖的整個服務框架。
本篇介紹到這裏,接下來會詳細介紹各個服務的實現。在此以前,下一篇先介紹一些通用的基礎機制設計和實現。