1. 程式人生 > >【遊戲框架】網遊的跨服玩法是如何實現的?“跨域體系”架構設計思路

【遊戲框架】網遊的跨服玩法是如何實現的?“跨域體系”架構設計思路

一、前言

這篇文章主要講的是網遊跨服遊戲的實現,從底層架構到上層邏輯的搭建都會涉及到,框架設計需求分析。

二、原文

三、正文

網遊的跨服玩法是如何實現的?“跨域體系”架構設計思路
這裡寫圖片描述

作者/江貴龍

  雖然遊戲市場競爭激烈,產品格局變動較大,但遊戲產業一直處於穩步增長階段,無論是在端遊,頁遊,手遊還是已經初露端倪的HTML5遊戲。可以預見,遊戲型別中,MMOARPG遊戲仍然會是引領市場的主流趨勢,貢獻著大部分流水,市場上也仍然在不斷湧現精品。研發團隊對MMO遊戲的探索從來未間斷過,從付費模式的改變,到題材多元化,次時代的視覺效果,更成熟的玩法及數值體系,本文主要針對跨服玩法上的探索和實現做一些思考和分析。

  根據2016年《中國遊戲產業報告》資料顯示,隨著遊戲人口紅利逐漸消失,獲取使用者的成本居高不下,幾年來至少翻了十倍以上,目前平均導量成本頁遊為10~15元/人,手遊在15~20元/人,其中IOS上成本30~50元/人,“洗”使用者模式的效果正在變得微弱,使用者流失嚴重。讓我們先來看看滾服玩法的侷限性,滾服洗量模式下存在著如下的弊端:
  這裡寫圖片描述
  在上述背景下,一款長留存,低流失的精品遊戲就成了平臺方,渠道商,研發方追捧的目標,設想一下,如果讓所有伺服器玩家通過“跨域體系”實現自由暢通互動,在此基礎上,玩家可以體驗到前所未有的“國戰系統”——7×24小時晝夜不停服的國家戰爭,隨時開戰;突破單地圖承載容量極限的國戰對決,帶來真正萬人國戰的刺激體驗,形成全區玩家能夠互動的遊戲社交環境。依託平臺運營來打造一款真正意義上擺脫傳統遊戲運營模式的全新產品,為平臺吸納足夠的市場份額,大幅降低流失率。

  我們的藍圖是開創“1=1000” 模式,讓所有玩家,身處一個伺服器卻如同同時存在於所有伺服器,這種打破伺服器屏障的設定,杜絕了遊戲出現“被迫滾服”現象出現,玩家不用再擔心鬼服人煙稀少,不用擔心交易所一無所有,所有的資料共享,讓玩家輕鬆Hold住全世界。
這裡寫圖片描述
專案組當時面臨的現狀是遊戲各種檔期計劃、宣傳推廣安排都已經就緒,兩個月後該獨代專案要在騰訊平臺按時上線,開發不能因引入跨服機制而導致所有完成度100%的功能都要去分別去增加跨服的支援,而技術人員在跨服功能開發這塊經驗的積累上也不充分。

技術小組分析了時下專案的現狀,跨服業務需求及現有的框架結構,明確了幾點原則:

  1. 為了實現跨服,遊戲程式碼從底層架構到上層業務邏輯的程式碼改動成本儘量降低
  2. 業務邏輯裡儘量少關心或者不用關心是否在本服或者跨服,降低開發人員的跨服功能開發複雜度,提高開發的效率,縮短開發週期。那麼,我們需要解決哪些技術疑點呢?

客戶端直連還是伺服器轉發

方案A,直連。如果直連,那麼,跨服玩法時客戶端要維持兩個連線,在跨服裡,要模擬玩家登陸,繫結session的過程,遊戲服和跨服兩邊要同時維護兩份玩家資料,如何做到資料的同步?跨服要暴露給玩家,需要有公網訪問IP和埠。對客戶端連線管理來說較複雜。

  方案B,轉發。如果通過大區伺服器訊息轉發,那麼,伺服器之間做RPC通訊,連線管理,訊息需額外做一步跳轉,效能能否滿足?跨不跨服,對於客戶端來說透明,跨服隱藏在大區之後,更加安全,不需再浪費公網IP和埠。

  綜合考慮了下,採用了B方案。

1. RPC框架設計需求

那麼,我們需要先準備一套高效能輕量級的RPC框架。業界有很多典型的RPC框架,比如Motan、Thrift、gRPC、Hessian、Hprose、Wildfly、Dubbo、DubboX,為什麼我們還要重複造輪子呢?綜合考慮了下,框架要滿足以下幾點業務需求:

  1. 該框架要簡單、易用、支援高併發的跨服請求;
  2. 根據現有的遊戲伺服器框架,會有很多定製化的場景;
  3. 通過NIO TCP長連接獲取服務,但無需跨語言的需求;
  4. 支援同步請求,非同步請求,非同步回撥CallBack;
  5. 要有服務發現的功能,要有Failfast能力;
  6. 具備負載均衡,分組等路由策略;
      基於有以上的訴求,結合團隊以前的開發經驗,於是就決定自主研發。我們選用的技術棧有 Netty、Apache Commons Pool、Redis等。

      框架分為服務提供方(RPC Server)、服務呼叫方(RPC Client)、註冊中心(Registry)三個角色,基於Redis為服務註冊中心,通過其Pub/Sub實現服務動態的註冊和發現。Server 端會在服務初始化時向Registry 註冊宣告所提供的服務;Client 向 Registry 訂閱到具體提供服務的 Server 列表,根據需要與相關的 Server 建立連線,進行 RPC 服務呼叫。同時,Client 通過 Registry 感知 Server 的狀態變更。三者的互動關係如圖:
    這裡寫圖片描述
    通過Global server提供路由策略,負載均衡策略,分組策略。具備 Failfast 能力,保障RPC服務一定程度的高可用。

2. RPC請求的有序性

連線池在設計過程中,比較重要的是要考慮請求的順序性,也就是先請求的先完成。如果玩家的跨服請求通過不同的RPC連線併發執行,就有可能單個玩家請求因錯序而導致邏輯矛盾,比如玩家移動,見圖2:
這裡寫圖片描述
  玩家移動是很頻繁的,如果A請求讓玩家從位置1移動到位置2,B請求從位置2移動到位置3,有可能B請求先被跨服接收處理,這就會產生邏輯問題。

  那麼,如何做到請求的有序性呢?其本質是讓同一份資料的訪問能序列化,方法就是讓同一個玩家的跨服請求通過同一條RPC連線執行,加上邏輯上的有效性驗證,如圖3所示:

這裡寫圖片描述

3. 同步RPC實現細節

限於篇幅,這裡只講同步請求的RPC連線池實現。同步請求的時序圖如圖所示:
這裡寫圖片描述
  上圖為進入跨服戰場的一次同步請求,場景切換控制器StageControllAction發起進入跨服戰場的請求applyChangeByBattlefield(),場景管理器StageControllManager首先要呼叫登入跨服的RPC請求GameRpcClient.loginCrossServer(LoginCrossServerReq),跨服RPC請求的工作流是這樣的:
  這裡寫圖片描述
  該請求第一步先從連線池裡獲取一個連線RpcClient rpcClient = rpcClientPool.getResource(roleId),然後發起一個同步請求RpcClient.sendWithReturn(),等待直到結果返回,然後把資源歸還連線池。

  我們重點來看看sendWithReturn程式碼實現:

這裡寫圖片描述
  測試場景為分別在連線數在1,8,併發數1,8,資料大小在22byte,94byte,2504byte情況下,做測試,訊息同步傳輸,原樣返回,以下是針對同步請求壓力測試的結果(取均值):

這裡寫圖片描述

伺服器之間主動推,還是被動拉取

1. 被動拉取模式(Pull)

  由於我們的遊戲伺服器和跨服伺服器程式碼基本一致,所以只要能在跨服中獲得遊戲功能所要的資料,那麼,就能完成任何原有的功能,並且改造成本基本為零,我們選擇了被動拉取。

  這裡要提出一個概念:資料來源的相對性。

  提供資料方,C向B請求一份資料,B是C的資料來源,B向A請求一份資料,A是B的資料來源。

這裡寫圖片描述
一個玩家跨服過去後,往遊戲原服拉取資料的細節圖如圖:
這裡寫圖片描述
  玩家先跨服過去,loginCrossServer(LoginCrossServerReq),然後,在用到任意資料時(主角、技能、坐騎、裝備、寵物等),反向同步請求各個系統的資料。

  我們的實現如下圖所示:

這裡寫圖片描述
這裡寫圖片描述
1. 如果玩家在本服,和調整前一樣的處理流程,如果玩家在跨服,客戶端請求的指令,釋出的事件,非同步事件需要在場景Stage執行緒處理的,就轉發到跨服,需要在其他個人業務執行緒(bus),公共業務執行緒(public)處理的,仍舊在本服處理。
2. 場景業務執行緒不再允許有DB操作。
3. 內部指令的轉發、事件分發系統、非同步事件系統要在底層支援跨服。
4. 玩家在登入本服時就會構PlayerTemplate, 場景用到的資料會實時更新,玩家去跨服,則會把場景中用到的資料PlayerTemplate主動推送給跨服。主動推送模式如下圖所示。
這裡寫圖片描述
這裡寫圖片描述
看下事件分發程式碼的改造:
這裡寫圖片描述
這裡寫圖片描述
  如下圖,舉個例子,在跨服怪物死亡後,會丟擲 MonsterDeadEvent事件,在跨服程序直接處理場景的監聽對應的邏輯:

  場景中道具掉落,屍體處理;其他的監聽邏輯拋迴游戲服處理,根據這事件,任務模組處理完成任務,獲得獎勵;成就模組處理完成成就,獲得獎勵;主角模組獲得經驗,金幣等獎勵;活動模組處理完成活動,獲得獎勵。

這裡寫圖片描述
  其他方面的優化1. 訊息組播機制

  訊息組播的優化,在跨服,來自同一服的全部玩家廣播從分別單獨訊息轉發,改成一個訊息發回本服,然後再廣播給玩家(比如來自同一個服n個玩家,原本廣播一條訊息,伺服器之間之間要處理n個RPC訊息,現在只需要處理1個訊息,降到了原先的1/n)。

這裡寫圖片描述

2. 通訊資料量

  一個完整的PlayerTemplate模版資料由於包含了玩家在場景裡用到的所有資料,比如角色、寵物、坐騎、裝備、神器、法寶、時裝、技能、翅膀等等, 資料量比較大,平均能達到5KB左右,需要在伺服器之間傳輸時做zlib壓縮,比如,做了壓縮後,11767 Byte的玩家資料能壓縮到2337Byte,壓縮率可達到19.86%。

3. 序列化/反序列化

  改造前,所有的請求都需要先在本服做AMF3反序列化,如果請求是需要轉發到跨服的,再通過JSON序列化傳輸給跨服,在跨服通過JSON反序列化,最終該請求被處理。

  但實際上,中間過程JSON序列化和反序列化似乎是沒有必要的,經過改造,對需要轉發給跨服的請求,在本服先不做AMF3反序列化,傳送到跨服後再處理,這樣就少了一次JSON的序列化和反序列化,同時收益了另外的一個好處:降低了傳輸的位元組。

這裡寫圖片描述
這裡寫圖片描述

4. 記憶體佔用優化

  Oracle JVM目前只能在JVM停止執行的時候才能做到釋放佔有記憶體,直到下次重啟,所以為了防止資源浪費,各種型別的跨服伺服器,遊戲伺服器都需要設定不同的啟動引數。啟動引數的設定根據我們自行設定的公式,如圖所示。
這裡寫圖片描述
  但記憶體佔用仍然會經常突破預警線90%,由於一旦系統分配記憶體發現不夠時,就會觸發自我保護機制,進行OOM killer,所以需要預留很大的記憶體給每個JVM程序,而且每次維護的時候去指令碼修改記憶體也比較麻煩。
  這裡寫圖片描述
  
  記憶體佔用狀況如上圖,伺服器更新維護後,記憶體佔用一路上揚,一直到最後維持在一定的值,不會回收,除非等下次維護或者系統觸發OOM killer。

  基於阿里 JVM 1.8,只要開啟-XX:+DeallocateHeapPages,CMS能在不重啟應用的情況下把不使用的HEAP歸還給系統的實體記憶體,這樣,我們就不需要預留很多空間給JVM,再也不用擔心被誤殺了。

  拿我們一款內測階段的遊戲舉例,使用了ALI JVM後, 64記憶體配置的機器最後開到了24個新區,相比起以前64G記憶體的機器,單臺只能放9個獨立的遊戲區的狀況下,單區的成本將會節省62.5% 機器資源,非常可觀。完美的解決了記憶體經常吃緊的問題,並大幅節省了成本,這裡特別感謝阿里雲團隊和@坤谷提供黑科技,大家有需求的話,可以去申請成為種子使用者。

這裡寫圖片描述
  上圖就是使用了Ali JDK後的鋸齒形效果,每隔一定時間閒置記憶體會被系統回收,這在Oracle JVM是難以做到的。

5. 伺服器分組機制

  不定向跨服是指任意遊戲區的玩家都有可能匹配到一起進行遊戲玩法的體驗,比如跨服戰場,比如跨服副本匹配,如圖所示(分別表示伺服器分組前和分組後)。
這裡寫圖片描述
這裡寫圖片描述
  如何在遊戲正式大區中選擇幾個服做灰度服,又不影響不定向跨服體驗,以及如何解決新老服玩家戰力發展不在同一起跑線而導致的不平衡問題曾一度讓人糾結。

  比如遊戲產品推出了大型資料片,想先做下灰度測試,讓1~4區的玩家先做下新功能的體驗,同時又能防止玩家穿了一件舊版本不存在的裝備而在跨服環境下報異常,根據運營需求通過分組,就很完美的解決了上述問題。

6. 戰區自動分配機制

  定向跨服是指在一定時間內會固定參與跨服玩法的幾個國家,常用於戰區中國家之間對戰,如圖所示,需要運營在後臺配置;當一段時間後,隨著玩家流失,又需要運營根據戰力進行戰區的調整,對運營人員的要求比較高。
  這裡寫圖片描述
  調整後,每一種基於戰區的跨服型別都可以自定義調整時間間隔,到時間點全域性伺服器(global server)系統自動根據全區的活躍戰力匹配進行調整,讓運營人員從繁雜的配置中解脫出來。

7. 跨服斷線重連機制

  比如戰場系統或組隊副本,由於網路狀況而掉線,如果重新登入後,沒法進入,將會嚴重影響戰場的戰況,順風局馬上就可能會變成逆風局,主力DPS掉線副本就有可能通不了,這個機制就彌補了這塊的缺陷。

8.支援的玩法

  目前,我們已經能支援任意的遊戲區玩家可以到任意的跨服伺服器進行遊戲功能的體驗。比如已經實現的跨服組隊副本、跨服戰場、跨服國戰、跨服皇城爭奪、跨服資源戰、蟲群入侵戰、跨服押鏢、挖礦爭奪等。

  也支援玩家在本服就可以進行跨服互動,比如和別的區的玩家聊天、加好友、送禮等無縫互動,及國家拍賣行,世界拍賣行的跨服貿易。甚至支援玩家穿越到另外的遊戲區做任意的遊戲體驗,比如一區的玩家聽說二區服在舉行搶親活動,你可以跑到2區去觀賞參與,也跑到任意的區的中央廣場去顯擺你的極品套裝。

跨服線上資料

  跨服定向玩法有戰區國家玩法,蟲群入侵,跨服押鏢,挖礦爭奪, 跨服皇城爭奪,跨服國戰等,如下圖所示,我們可以看出這種玩法的規律:每次活動開啟,跨服就會迎來一波波玩家湧入,活動一結束,玩家就會離開,4個跨服程序支援了7600線上的玩家。
這裡寫圖片描述
  跨服非定向性玩法有跨服組隊副本,跨服戰場等,支援負載均衡,可以隨時動態增加跨服。這些玩法的規律是24小時隨時可以體驗進入,線上比較穩定,8個跨服程序支援了28000線上的玩家。

技術架構

下圖為跨服通訊拓撲圖,屬於整體架構的核心部分,關於這一部分的說明見圖表:
這裡寫圖片描述
這裡寫圖片描述

小結

  此套架構歷經了《大鬧天宮OL》、《諸神黃昏》、《暴風王座》、《驚天動地》,《三打白骨精》、《英雄領主》、《封神霸業》等先後近兩萬組伺服器執行的驗證和團隊的技術積累。

  本文從當前遊戲市場發展的背景出發,提出了設計自由互動的“跨域體系”的必要性,然後在實現跨服架構過程中對設計目標、原則、存在的技術難點進行了思考,實現了一套用於跨服通訊的高吞吐的RPC通訊框架,先後體驗了被動拉取模式帶來的坑,和改成主動推送模式帶來的便利。並且,對該架構設計在訊息組播,通訊量,訊息序列化/反序列化,伺服器分組,戰區自動分配,斷線重連等進行了多方面機制的分析及深度優化,最後上線實踐做了可行性驗證,提供了強有力的資料支援,總體表現穩定流暢。