《大唐豪俠》架構開發紀實

>>>  創業先鋒 眾人拾柴火焰高  >>> 簡體     傳統

游戲介紹

《大唐豪俠》是網易公司2006年主推的一款網絡游戲。它是一款以唐朝為背景的武俠游戲,采用即時戰斗機制。游戲創作人員在《大唐豪俠》立項后,都表現得躍躍欲試,急欲一展身手。根據以往的開發經驗,我們最終將《大唐豪俠》的設計容量定為5000人,即游戲允許同時在線的玩家上限為5000人。 明確了基本目標,程序開發人員將要面對多個挑戰,其中最主要的兩個是:

1. 如何表現即時戰斗效果?
2. 如果支撐5000玩家?

前者體現在畫面效果和戰斗節奏上,主要與渲染有關,不屬于本文討論的重點。本文主要探討第二個問題,即架構上的考量。

第二個問題之所以是一個挑戰,是因為存在著這樣一種矛盾,即單服的運算能力不能滿足游戲對運算能力的需求。

相對于回合制游戲,采用即時戰斗機制的游戲需要實時計算更多的數據,例如在回合制游戲中,回合發招完成后才開始計算傷害效果,而即時戰斗類游戲會在持續播放戰斗動畫的過程中不斷產生計算需求,只要播放到關鍵幀就要計算傷害效果。這樣,即時戰斗類游戲計算傷害效果的間隔更短,頻率更高,而對CPU的運算能力提出了更高的要求。在最近幾年,計算機技術的發展很快,可以用日新月異來形容,雖然雙核、多核、多CPU的計算機正逐步取代單CPU的計算機,但仍尚未成為市場主流,而讓單CPU配置的主流服務器支撐這么多玩家即時戰斗多少還是會有些力不從心。因此如何進行游戲服務器集群的架構,從而有效地利用目前主流機型為《大唐豪俠》服務,就成為了一個挑戰。

在游戲架構里,游戲的同步策略是很重要的部分,它關系到游戲運營時對網絡帶寬的要求。同步策略越優秀,網絡帶寬的耗用就越少,游戲過程中的流暢度也會越好。《大唐豪俠》的總監趙青先生曾撰文詳細闡述過同步策略方面的問題,所以本文就不在這里重復了。本文著重探討服務器構架過程中,面對各種技術方案,我們是如何進行考慮和選擇的。

技術選擇
從宏觀的層面看,我們主要考慮了以下幾個方面的問題。但總的原則相當清晰:“簡單就是美”,KISS(Keep It Simple,Stupid)。這一原則同時兼顧到了項目的進度和遠景目標。

單服/多服
在當前主流服務器配置的情況下,要支持5000人同時在線,就只能選擇多服務器架構,單服務器無法勝任這樣的要求。事實上,分布式的服務器架構還給我們帶來了易擴展的好處。只要我們在設計游戲服務器時,讓游戲服務進程(GAS,Game Server)做完全相同的事情,那么就能很容易地加入新的服務器。新服務器的加入,既可以在一定程度上提高支持同時在線玩家的能力,也可以分担其它服務器的負担。

多線程/多進程
通常,用多線程編程方式構建應用程序,是利用多核或多CPU計算機性能的主要方式。但用多線程方式開發游戲服務器并不是非常適合。

眾所周知,成功的游戲離不開豐富的玩法,玩法越豐富,越能吸引玩家,玩家也越不容易感到枯燥,但這樣一來,游戲的邏輯也會變得更加復雜。此外,游戲的輸入主要來自玩家,玩家使用物品或者使用技能都可看作是對系統的輸入。另外,由于存在著用戶之間的交互,因此一個玩家的行為往往對其它玩家存在著影響。這些因素的存在,增加了BUG出現的幾率。由于硬件和操作系統的原因,線程切換時間不完全一致,在這種情況下,要對某些BUG進行復現則相當困難。

綜合這些分析,可以簡單地說,以多線程方式開發,既有開發方面的難度,也有維護方面的難度。相比而言,多進程方式既可以滿足多服務器結構的要求,在一定程度上還規避了某些多線程的問題。

大容量/小容量
通常,我們會希望在玩家視野所及的地方越熱鬧越好,這樣,人氣就會很旺。那么是不是在每個游戲服務進程中,支持的玩家也是越多越好呢? 實際上并不完全如此。 所謂玩家至上,是指讓玩家在游戲進行的過程中能終保持良好的游戲感覺。我們知道對于復雜程序來說,完全消滅BUG幾乎是不可能的,游戲服務進程會因為各種BUG或其它各種原因而崩潰、宕機。一個游戲進程中的玩家越多,一次宕機影響到的玩家數量也會越多。如果排除該問題需要很長的時間,而游戲進程又連續崩潰,那么游戲玩家的耐心和熱情將會受到很大的打擊。 顯然,我們是無法完全避免BUG的,也無法完全避免宕機,但是我們可以努力降低這些問題帶來的負面影響,使受影響的玩家保持在一個較少的數量上。這樣看來,一個進程中容納的玩家數就不應該太多,從目前的主流服務器配置來評估,單個CPU支持1000人是比較合理的數量級。

無縫地圖/多地圖
國外幾款游戲大作的場景多是無縫拼接起來的,以《魔獸世界》為例,當玩家從西大陸進入東大陸時,會經過一個狹長的谷道,通過谷道需要幾十秒時間,客戶端有充足的時間在玩家行走過程中加載目的地的地圖信息。沒有了顯式地切換場景,玩家的感受可能會更連貫,但是在技術實現上,無縫地圖方式還有一些其它方面的因素要考慮,它是一個綜合問題,實現起來會比較復雜。

而在多地圖方式下,從一個場景到另外一個場景,要通過NPC對話或者經過TRAP點顯式控制場景切換,例如玩家如果想從新手村到長安,就要和驛卒對話,選擇要去的目的地,玩家選擇長安后,在客戶端,通常會顯示重新加載地圖文件的進度條,根據地圖文件的大小和實現技術的不同,加載一般需要幾秒到十幾秒不等。
雖然多地圖方式比無縫地圖方式在表現上要稍差一些,但多地圖方式的技術實現相對簡單,同時,也會簡化和規避一些其它的技術問題。例如如果是無縫地圖方式,開發使用的地圖編輯器就需要能支持多人同時修改同一個地圖文件。

動態/靜態負載均衡
在分布式架構中,負載均衡是必須要面對和考慮的問題。 某些場景或者場景中的某個區域,可能會因為多種因素的綜合效應聚合起相當數量的玩家,例如在門派入口處,玩家會自發的在這里擺攤交易,形成商業區;又如戰場中的攻防要塞,是攻守雙方爭奪的焦點,也是玩家聚集的地方。如何才能保證在這種玩家聚集的情況下,仍然能讓他們感覺流暢,玩得暢快呢?這就需要考慮服務器的性能上限,調整服務器支持的人數,進行負載均衡。

負載均衡主要有兩種策略:動態負載均衡和靜態負載均衡。Big World引擎(網易《天下II》采用)采用動態負載均衡,它把游戲世界(無縫地圖方式)分為多個區域,每個服務器承載其中的幾個區域,當某個區域負載較高時,就將該區域細分為幾個更小的區域,并把其中某些區域的數據遷移到其它服務器上,讓其它服務器來承載。但是動態負載均衡對架構設計要求較高,還要考慮如何確保在數據轉移過程中,玩家及其它相關對象狀態的遷移、組隊信息的更新等等能夠保持正確,其中的工作量不小。

《大唐豪俠》采用靜態負載均衡,我們把游戲世界分成多個場景,每個游戲服務器承載其中的幾個場景,游戲場景的大小在設計時就已經確定下來了,不會在運營期間再進行動態調整。服務器的負載可以在游戲服務器啟動前進行評估,評估時要考慮的因素主要包括地圖是否是玩家特別喜歡的場景、地圖是否經常被運營商選取進行線上活動以及過去的運營情況等。這樣,在每周例行維護時,我們就能評估出每張地圖的人數,從而估算出它們的負載,比較合理地把它們分配到不同的服務器上。雖然靜態負載均衡比動態負載均衡缺少靈活性,但是實際效果也是相當不錯的。

C++/腳本
采用即時戰斗機制的游戲有一定程度的密集運算,因此,我們在開發過程中,一直在注意避免因運行效率導致設計目標無法達成的問題。計算量較大的部分主要是每幀對象的狀態更新、尋路和戰斗的效果計算,我們選擇用C++實現這些功能讓運行效率最大化,而其它非密集運算的功能,如普通的送信任務、找人任務等游戲玩法,則可用腳本方法來實現。 至于選擇哪種腳本語言,則是仁者見仁、智者見智了,在開發《大唐豪俠》時,我們更熟悉Python,并且這門語言也有非常多的優點(除了速度慢了點以外),因此就選用了它。

界定何時該用腳本,何時該用C++有一個簡單的標準,即改動不頻繁,計算量大的應該用C++;改動頻繁,計算量小的應該用腳本。使用C++,為了提高運行效率,會有較多的時間花在編譯上;而腳本語言則犧牲了運行效率,獲得了運行期間動態變化的能力。我們知道,游戲開發是一個不斷響應快速變化的過程。如果頻繁更新的部分也用C++來實現,則會顯著的增加編譯時間,開發的效率會很低。

雖然此處將這些因素分開列舉,但實際上,這些問題并非獨立存在,它們之間也會產生相互影響。例如多服務器架構是多進程間的協作,多進程的協作可自然延伸為多服務器架構。又如多場景地圖和靜態負載平衡都在一定程度上降低了開發的難度,多場景地圖為服務器的靜態負載平衡提供了條件。

設計要考慮的當然遠不止上面談到的這些內容,設計既是系統化的工作,也是一個尋求平衡的過程,這里只是站在宏觀的層面,羅列了較為重要的部分,而這些部分就決定了游戲的架構最終會是什么樣子。

游戲架構
基于上面的分析,服務器架構就變得很清楚了。圖01簡單的描述了架構中的服務器以及它們之間是如何進行交互的,虛線表示服務器間通過短連接交換信息,實線表示服務器間建立了長連接。為簡單起見,這里只畫出了2個GAS,實際上一共有5個GAS。

其中,GAC是游戲客戶端(Game Client),其它是服務器,這些服務器的職責分別是:

GCC(Game Cluster Controler)
GCC是游戲服務集群(Cluster)的核心,是大腦,只有GCC才能決定集群級別信息的準確性和唯一性。
GCC肩負登錄服務器的功能,玩家通過游戲客戶端輸入用戶名和密碼,隨后用戶名和密碼被發送到GCC,由GCC轉發給認證服務器,通過認證的玩家信息會通過DBS從數據庫中取出,并在GCC上判斷玩家應該連接的GAS,接著登錄成功協議和重連協議被發送到客戶端,客戶端按照重連協議的指示連接到指定的GAS并進入指定的游戲場景。

GCC也是游戲世界中的位置寄存器,保存著所有在線玩家的位置信息。任何涉及跨GAS玩家的信息交換和事務處理,或者交給GCC處理,或者向GCC查詢目標玩家的位置后由GAS直接與目標GAS協商。

DBS(Database Server)
DBS負責把游戲世界中的持久化數據存儲到存儲系統中,DBS把GAS/GCC與存儲系統隔離開來,GAS和GCC完全不需要知道后臺的存儲系統是什么,數據是如何被存儲的是由DBS來決定,它即可以存為文件,也可以存到數據庫中。《大唐豪俠》的后臺存儲采用MySQL數據庫。
鑒于DBS能直接訪問后臺的存儲系統,非常重要和敏感,因此DBS只接收來自GAS和GCC的鏈接,并放在防火墻后面保護起來。DBS把GAS/GCC發來的協議轉換為sql語句丟給MySQL服務器執行。DBS也會負責一部分的游戲邏輯,如離線玩家數據的處理;同時還會分析請求的特點,區分出請求能否并行執行,把能并行執行的并行處理,不能并行執行的就串行處理。

GAS(Game Server)
GAS接收客戶端發來的協議,過濾非法數據包,并分析協議中的內容。例如分析玩家是要使用道具還是要使用技能,然后按照游戲玩法規則,根據玩家的行為完成游戲邏輯的計算。游戲的大部分玩法都在GAS上處理,只有少量的全局性邏輯或跨服務器的玩法會由GCC處理,離線玩法則主要由DBS處理。

在這些服務器中,GCC是大腦,所以如果GCC崩潰,游戲服務集群狀態的一致性就無法保證,游戲就得立即停下來。而如果DBS崩潰,用戶的數據無法讀取,玩家就無法登錄,也無法保存玩家數據,這樣可能會導致玩家數據丟失,所以游戲也得立即停下來。相對而言,如果GAS崩潰,問題就不會有這么嚴重,主要只影響到該服務器上在線的玩家,我們可以重啟GAS并將其重新加入集群中,GAS就能繼續提供服務了。

為簡單起見,我們沒有設計恢復處理,而是選擇了一種簡單的處理方案:當GCC和DBS崩潰時,集群關閉;GAS崩潰時,自動重啟重新加入集群。從運營效果看,這種方案不但能讓我們快速發現問題,找到問題,避免了為實現容錯而增加的復雜性,也避免了數據不一致性對游戲系統和玩家帶來的損失。

總結
隨著互聯網的發展,越來越多的人享受網絡生活,MMOG是其中最具吸引力的娛樂方式,玩家也不僅僅滿足于小范圍內的相互交流,他們期望能夠與來自不同地域更多的玩家一起在游戲中探索、相遇、結識,因此,如何在一個游戲世界支持更多的玩家,就成為MMOG游戲開發的一個挑戰和難題。分布式/集群是對該問題行之有效的解決方案,雖然在這種方案的實現過程中也會面臨著許多挑戰,但越來越多的游戲,根據自身的特點找到了合適的平衡點,它們的解決方案也一再地在實踐中得到證實。本文站在《大唐豪俠》開發的角度,分析和探討適合《大唐豪俠》的游戲框架,希望這種框架對其它游戲的設計也將有所啟發。


創游傳媒 2011-02-19 08:14:44

[新一篇] 《劍俠情緣網絡版》開發回顧

[舊一篇] 《天機online》化蝶的開發之美——天機回憶錄
回頂部
寫評論


評論集


暫無評論。

稱謂:

内容:

驗證:


返回列表