《王者榮耀》2億使用者量的背後:產品定位、技術架構、網路方案等

IT技術精選文摘發表於2018-05-17

1、前言


作為一個國民級手遊,《王者榮耀》公測幾年來的表現一直很強勢。在耀眼的成績背後,到底是什麼樣的技術支撐了這個使用者量破2億的遊戲?王者上線前後在技術上有哪些變化、又是如何處理網路問題的?

《王者榮耀》能夠成為如今國內最成功的手遊,其後方成熟的技術團隊可以說是功不可沒。這個曾經在端遊時代主導搭建RTS遊戲《霸三國》框架的技術團隊,在轉型做MOBA手遊《王者榮耀》後為遊戲提供了巨大的支援。但這個過程也並非一帆風順。

2、內容概述


今天分幾部分和大家介紹王者後臺開發過程中的一些內容和思考:包括王者整個背景的介紹,後端的架構,上線之後做了什麼樣的調整,還有網路同步方案,反作弊方案等。

目前遊戲的伺服器架構主要由“遊戲大廳”和“PvP”2個部分組成,而在不斷探索中,其後來又在架構中加入了Proxy中轉伺服器,也正是這個伺服器的加入為《王者榮耀》解決了後來“安卓、iOS”同服等一系列出現的問題。此外,他還介紹了《王者榮耀》在網路協議以及同步方案上的一些嘗試,並一一覆盤了這些嘗試的優劣勢,並解答了為什麼,最終遊戲會放棄TCP協議(傳輸控制協議)與曾經在《霸三國》中所使用的CLIENT-SERVER結構(C/S結構),並且轉而使用了UDP協議(使用者資料包協議)與幀同步同步方案

我能透露的資料是,現在王者後端的機器大概是4600多臺機器,我們的容量也有一定的擴充套件,程式數目是4萬多個。

3、《王者榮耀》的產品背景:原本是RTS端遊《霸三國OL》


2012年,我們當時做端遊遊戲,是王者的前身。最開始是偏向RTS的遊戲,後來我們把它改成端遊的MOBA,後來做手機上面的MOBA即王者。從2012年開始做RTS遊戲到2013年,從多控制單位的RTS遊戲 變成MOBA遊戲,到2014年啟動王者的預研,再到2015年2月份我們把很多的人力(大概100多號人)投入做王者開發,時間比較短。6月份的時候,大概4個月開發時間,我們就開啟了王者的對外技術測試,8月份開始做不刪檔測試,聽了主論壇就知道,那時候我們叫英雄戰跡。再到後來《王者榮耀》10月開始不限號。時間很短,任務也很重,壓力也很大,主要全量的開發時間就是3-4月,這也決定我們當初技術選型方面的考慮。

做王者之前,我們做的霸三國,最開始是偏RTS的遊戲,後來我們改成了PC上的MOBA遊戲。

前面我們提到《霸三國OL》的RTS遊戲,其實大家可以可以瞭解一下這個完成度已經是比較高了,但玩起來的話還是有一些問題,這個方案就被放棄了。

《霸三國》的玩法是,玩家可以在戰前通過排兵佈陣構成自己局內的策略,通過控制多個單位,技能釋放、兵種特性的釋放形成對抗。我們最開始做《霸三國》的時候客戶端引擎是unreal,但在做王者的時候引擎用unity,3-4個月的時間,本身從程式碼層面沒有任何東西是搬過來用的,全部都需要重寫。

4、《霸三國OL》帶來的技術啟示


做端遊《霸三國OL》的這段經歷,給我們做王者帶來很多相應的啟示,比如策劃、程式及整個團隊對MOBA的理解。另外當時在做端遊RTS、MOBA的時候,我們採用了CS(Client-Sever)的模式,但其實在過程中有借鑑類似幀同步的概念:例如在斷線重回對視野的處理這塊。

傳統的做法是重回時會發當前的映象和後續的其他下行通知資訊,但傳統做法會有一個問題,如果新增其他的場景內模組的時候,根據場景內包含的當前的各種物件、所在狀態的各種各樣資訊,都需要把這些東西打包發下去,在後續開發、維護的時候挺麻煩的。我們的做法,就是類似幀同步的理念,把伺服器下發的所有序列包做快取和按順序重發,讓客戶端做快進的表現,它的概念和幀同步其實是比較類似的。還有一點,就是預留設計彈性,最開始RTS每個玩家最多可以操作5-8個進行對抗,到後來改成MOBA遊戲,只能操作一個英雄,加入各種各樣的場景,我們本身的技術框架沒有進行顛覆性的大改。

5、《王者榮耀》的整體技術架構


王者目前後臺的整體架構的設計是源自產品的需求,大家玩過王者的就知道,PVP的對抗是不分割槽服的,你登入微信1區可以和微信2區一起PVP,甚至ios平臺可以和Android平臺的人一起玩PVP,但是同時又保留了分割槽的概念,比如戰隊、排行榜是基於區的概念,區在王者裡面就是編號,是打在玩家新建角色上的Logo。

我們最開始做架構實現的時候,伺服器當時做得比較簡單,從原型開始只是保留了大廳和PVP伺服器這兩塊,它本身是分開的。PVP伺服器的使用類似CGI呼叫,可以分配資源使用,用完之後回收,不負責其他的東西,需要的東西從大廳拿,用了之後回給大廳,讓大廳回寫DB。包括大廳和PVP之間做直聯,後來把直聯改成中間的轉發,在王者裡面我們叫Proxy,相當於代理伺服器,遮蔽本身後端很多程式分佈的細節。因為王者本身的機器、程式很多,還有不同的路由規則,比如某些排行榜或者戰隊根據邏輯區的編號來確定有哪臺機器或者多臺機器進行處理,有些訊息採用隨機轉發或者多發廣播,都是由Proxy負責。

之後又加入了房間伺服器,它負責的是王者裡面匹配、排位相關的功能,怎麼樣把實力比較接近的人糅合到一塊兒玩,是由房間匹配伺服器來做相應的負責的。也會有戰隊和其他的伺服器。最後我們在上面加入了一個Adapter,作用是用本身已經部署的大區資源實現跨平臺匹配的功能。王者的後端架構,除了戰隊這樣的伺服器之外,所有其他的模組都可以線上擴容,或者在發現線上下降的故障時,從整個架構裡自動遮蔽掉。因為路由方式會限定比如一區、二區、三區到這臺機器處理,如果故障,影響的只是某幾個邏輯區玩家請求的處理,降低故障影響範圍。

王者目前的機器數量,可能每週都會發現有機器壞掉,至少有一臺機器宕掉,在架構裡面保證模組故障自動遮蔽和線上擴容,是非常重要的事情。整體結構比較像MMO的三層結構,MMO在騰訊有比較典型的三層級別的結構。大廳伺服器會根據玩家的所在區登入具體區的大廳伺服器。單個大廳程式可以承載2萬人,單個PVP可以承載1.2萬,小區登入微信一區還是二區就是角色Logo打在他身上。其實王者就是全區全服的結構,如果剝離了戰隊,它就是一個全區全服結構。不管是大廳還是PVP伺服器,其實每個都是按組的概念。我們可以線上擴容,如果組裡面某個宕掉,不會有什麼太大的影響。

王者現在外網有四個大區,比如Android手Q、Android微信、iOS手Q、iOS微信,還有搶先服。我們會用程式開關的方式,在大版本釋出之前,優先更新搶先服,這時候它不能和正式服玩家匹配在一起,因為他們的版本不一致。當全服釋出之後,它的版本更新一致之後,我們會開啟開關,搶先服的玩家可以和正式服的玩家一起進行PVP的匹配。

除此之外,我們還有專門的體驗服,是給策劃驗證相關設計的,體驗服保留可能刪檔的操作,但在外部正式環境這是絕對不允許的。

另外,以前的傳統手遊偏單機,就會做很多協議相容,客戶端版本沒有更新可以玩。但是王者裡的主要玩法是PVP,同時結合實現方式,不同版本的玩家不能匹配一起,所以我們沒有做任何的協議相容,因為這樣做起來也很麻煩

6、上線後的調整


上線後,王者本身的後臺架構,整個結構沒有做太大的改動,因為我們做端遊的時候,對這套結構比較清楚,我們知道哪個地方可能有什麼樣的問題,所以整個結構一直比較穩定。

但是我們做了相應的微調,做得最多的是網路本身的優化。王者上線的時候,市面上要求網路及時性強的即時PVP遊戲是比較少的。我們做了各種各樣的嘗試,比如在網路做CPU方面的效能優化、延遲、丟包等等,網路本身花的時間是最多的。

架構上的微調,像剛才提到的中轉模組,我們架構中大廳機器很多,PVP機器很多,架構中不需要每個程式知道詳細資訊,比如大廳伺服器不需要知道後面有多少房間伺服器,只需要知道後面有房間伺服器,可以訪問就OK。怎麼劃分、平衡負載、怎麼遮蔽後端故障節點,都是由Proxy路由功能在負責,只是它最開始比較像三層結構,我們把下面兩層劃分成彼此之間沒有交集的樹枝的概念,每組Proxy只負責一部分的大廳和PVP伺服器,因為這兩種伺服器在王者的伺服器裡面最多,但是後端都是通聯,它們彼此之間不會有互動,但是當我需要發廣播訊息的時候,比如有一個人發了一個喇叭,需要讓全服的人看到,就是由這個Proxy去轉發給其他的Proxy,讓對應的中轉伺服器傳送給大廳伺服器。

然後我們講Proxy Adapter,我們上線後最開始上線只有四個大區,手Q、微信、Android、iOS四個環境,最開始Android的玩家不能和iOS的朋友開黑。開始Android和iOS分開也有一定原因,我們之前設想Android會先更新,iOS後跟進,以保持版本更新的穩定性。但後來我們希望Android和iOS的玩家可以因為關係鏈一起開黑。所以當Android、iOS版本更新頻率一致時,我們希望不需要部署太多額外的機器資源和開發,直接利用Android和iOS已有的PVP伺服器和大區資源,打通Android和iOS的pvp。當Android玩家登入Android大區會連線到Android大廳,iOS登入之後連線iOS大區的大廳,當他們需要開黑的時候,我們通過Adapter把中轉模組所有的大區橋接起來,通過一定的演算法投遞到某個大區,投遞的選擇和大區資源佔比有直接關係,因為Android手Q在王者裡是最大的一個區,它所佔用的機器也是最多的。

7、網路同步方案


之前做霸三國的時候採用CS的模式,就是伺服器判定客戶端表現。為什麼我們在做王者的時候選用幀同步的方式呢? 

CS模式的好處在於:首先是安全,因為都是伺服器計算,客戶端不管怎麼作弊,它只是負責表現層面的功能,不會影響各種判定的結果。另外CLIENT-SERVER模式因為是基於結果的表現,所以中間可以出現丟包,丟包是可以被接受和處理的,只要最終的結果補發一致。幀同步在端遊用得比較多,大家比較熟悉的dota,還有星際,都是用的幀同步技術。幀同步本身對網路要求更加嚴苛,下發的執行序列是不允許丟包的,需要嚴格保證順序性,包是12345,就必須是12345,如果丟包,必須要等到丟的包完整到達之後才能順序後續執行。MOBA本身的單位比較多,同屏時客戶端最多有將近100個單位,假如一個AOE技能打到20個單位,然後中了一個debuff,CS狀態模式需要發這些資訊下去,可能潛在的同步狀態資訊是比較多的。

另外一個CS模式本身開發的方式,客戶端表現與伺服器的判定,要完美的匹配是比較困難的。比如我(的英雄)打出去一個法球,那伺服器還要算這個運動是多久、客戶端要跑多久,最後命中傷害了多少血。

我們之前做端遊MOBA的時候,一個英雄的技能我們開發要兩三週的時間。王者整個開發的時間是三四個月,這樣的時間壓力下面,我們用CS的方式搞不定,時間不夠。不過當時心裡也會比較緊張,因為當時市面上並沒有看到用這種方式做的強PVP的高及時性的手遊。幀同步本身網路抗抖動能力比較弱,因為不能丟包。幀同步的基本原理,大家有興趣可以下來自己瞭解一下。一般會有區分,是網狀還是主機模式。該技術的要點在於局內的運算都是基於客戶端運算,10個人每個人各自算一份,有相同的起始、相同的輸入、完全相同的中間運算邏輯,不存在真正的隨機過程,這時候運算的結果,理論上應該是一致的。甚至包括浮點數運算都不應該存在,因為它有精度的問題。包括很多碰撞,動畫,還有基本的數學運算庫都是後臺自己實現的,要去浮點整形化,避免客戶端的本地邏輯,這是最容易犯的錯誤,這是出現不同步最常見的原因。如果某個經驗不是很足的客戶端程式,寫程式時候用本地的程式碼做相應的邏輯,可能跑得越來越遠,10個人都是平行的世界。

整體的網路結構,大體看來是分三層:

  • 1)伺服器;

  • 2)客戶端邏輯層;

  • 3)客戶端表現層。


伺服器主要負責的功能有兩部分:一是收集所有玩家上行的輸入,把它按定時的間隔打包成輸入的序列,投放給所有客戶端;當客戶端出現丟包的時候,伺服器進行補發;還有把客戶端上行冗餘的資訊替換掉,比如有新的輸入到了,就把老的輸入Drop掉。王者我們的邏輯是66毫秒一次,1秒同步15個包,這是不能少的,因為幀同步不能丟包,資料包必須有嚴格的執行序列。

客戶邏輯層理解為客戶端本地的Sever,就是所有客戶端執行的結果必須強一致,不能有真的隨機,不能有本地邏輯,不能有浮點數的運算,就是10個客戶端拿到相同的輸入,產生結果必須一致。

客戶端表現層是根據邏輯層的資料去做Copy或者映象,然後在表現層進行平滑,幀數不一樣,但是不會影響最終的運算結果,隻影響動畫和動作的表現。

PVP通訊我們用的是UDP方式,最開始上線時我們是用的TCP技術,TCP在區域網的情況下表現還是不錯的,沒有什麼問題,但是當外網出現丟包或者抖動的時候,受限於實現方式,比如視窗、慢啟動各方面的原因,會發現當出現重聯的時候會非常卡,所以後來我們沒有用TCP,改為了採用udp。如果出現丟包,伺服器會在應用層做補發。udp受限於MTU的大小,大於MTU,出現丟包就可能會出現整包的丟失。所以我們也會有些比較大的包會在APP層由伺服器做分包,中間出現丟包再由伺服器補發,把零碎的包拼成整包再做解包。比較有價值的是udp包,比如我們以伺服器下行發給客戶端來做,過程中如果手機因為訊號抖動等情況,丟包是很明顯的,這時候下發的時候通過冗餘資訊的方式降低丟包,是比較有效的解決方法。

幀同步的訊息比較小,按照理論1秒15個驅動幀來算,20分鐘的錄影是10M左右。但是我們外網統計,正常的5V5對局20分鐘,錄影的大小大概是3M左右。伺服器會把玩家的操作做純記憶體的儲存,當出現丟包的時候,伺服器會通過編號快速找到快取資訊進行下發,同時根據丟包的情況,我們會計算給這個人傳送冗餘量的變化量。最開始傳送每個包會冗餘前面3幀的資訊,如果丟包嚴重,我們會嘗試冗餘更多資訊再下發。客戶端拿到之後會盡量壓縮邏輯執行的過程。幀同步有比較麻煩在於,它不像CS的模式隨進隨出,崩潰之後重回必須從一開始執行,中間運算過程不能少掉。

另外,我們也嘗試過其他的一些方法,比如客戶端上行之後,不需要伺服器定時的間隔去做收集然後下發,我們發現這樣做對手感提升的作用微乎其微,但它帶來的負面作用其實更大,因為不是一秒定幀的15個包的下發,你可能下發包的數量非常多,完全和這個人的操作習慣有關係,有可能一個人一秒之內產生了十幾二十個輸入,就需要把這些輸入染色編號之後對客戶端下發。客戶端因為收包很多,手機發燙就會很明顯。我們也有和其他部門合作,做類似於tcp的技術,大家直觀想到如果丟包就在io層做重發,但是實際的結果會發現,做的這個技術偏底層,所以對丟包的控制性不那麼靈活,而且可能出來的結果還沒有tcp本身好。

傳統的幀同步的方式會做延遲投遞,這個我們也有嘗試過。如果間隔時間內出現丟包,或者出現包下行的時網路波動,可以通過延遲投遞這種方式抹平抖和丟包的情況。我們嘗試過這個方案但最終沒有這樣做的原因在於:王者裡面一些英雄體驗起來感覺偏動作,對反應要求比較快,延遲投遞雖然確實抗抖動和抗丟包的能力不錯,但是手感上達不到我們的要求。另外,做CS方式的實現,一般都會有一個套路,客戶端提前表現,根據伺服器的表現做平滑或者拉扯,這個方案我們也嘗試過,但最終還是放棄了,因為這個技術會讓角色本身的表現有點發飄。客戶端本地一動,馬上客戶端表現就跟著動,但根據伺服器的下行,其實會做一些偏移或者修正。當網路抖動出現的時候,你會發現這個角色有一點發飄,所以這個方案我們放棄掉了。

幀同步方案,所有客戶端進行運算,期望產生一致的結果,但如果因為bug或者某個人使用修改器,跑出來的結果在某個時刻一定會和其他人不一樣,當不一樣出現,我們的說法是不同步了。我們會定時把一些關鍵資訊提取出來做hash,不同步的人的hash和其他人會不一樣。王者不同步率上線時大概是2%,也就是100局可能有2局出現一個人或者多個人運算結果和其他人不一樣。我們現在把不同步做到萬分之三,一萬局裡面只有三局出現這個情況。

這是怎麼提升的呢?如果你用幀同步一定會遇到不同步的問題,客戶端寫錯了,用了本地邏輯,可能浮點數的運算誤差達到那樣的臨界點,它就會產生運算結果不一致。我們的方法有很多:自動化測試,用機器人不斷跑,比如上新英雄之前,有指令碼測試不斷跑,看會不會產生不同步的結果;有專門的體驗服、搶先服大區,釋出到正式網路之前先測試,先小規模暴露問題,再解決問題;另外,當不同步的時候,我們會把這局整個錄影和客戶端間的log上傳和儲存下來,這樣可以根據錄影和中間執行的日誌序列快速的定位是哪個地方出現問題。

我們對延遲和單局質量也有相應的監控,這一局有沒有卡或者卡多少次,有沒有出現丟包,丟包多少,最大的延遲、最大的抖動是多少,我們都是有相應的記錄和統計。

同時,運營部的同學給我們提供了很多幫助,我們會有相關的網路測速、問題分析的SDK的合入。按照我們自己的經驗,玩王者的同學肯定都卡過,但真的不是伺服器的鍋,伺服器的效能沒有問題,而且一直都是很低的負載。

主要的原因有幾個:

  • 一是小區的頻寬比較繁忙,很多小區其實都是公用頻寬出口,比如有人在下電影、看直播,佔用了很高頻寬,你玩遊戲就可能會卡;

  • 二是wifi路由器延遲比較高,家裡的wifi路由器長期沒有重啟,因為它的程式碼也是人寫的,就會有bug,就會存在終端過多、通道干擾、其他大流量的應用下載情況,這也會影響你玩王者;

  • 還有就是手機訊號差、訊號抖動,wifi、4G空口丟包等。


我們其實在網路優化上做了很多的嘗試,例如根據丟包情況加大冗餘,然後優化我們各方面執行的效率,去減少CPU的佔用。王者後臺方面,有兩個點是我們一直努力在做的,網路優化和匹配機制,我們嘗試用各種各樣的方法,甚至後面也會嘗試用AI深度學習的方法,來更加精準的定位玩家本身的真實水平,讓他能夠匹配到更加真實的同等水平的對手和隊友,但網路這個問題還是現實存在,比如你進電梯玩王者它還是會卡。

公眾號推薦:

相關文章