《游戲服務器架構的演進簡史》要點:
本文介紹了游戲服務器架構的演進簡史,希望對您有用。如果有疑問,可以聯系我們。
游戲服務器端,是一個會長期運行的程序,并且它還要服務于多個不定時,不定點的網絡請求.
所以這類軟件的特點是要非常關注穩定性和性能.這類程序如果需要多個協作來提高承載能力,則還要關注部署和擴容的便利性;同時,還需要考慮如何實現某種程度容災需求.由于多進程協同工作,也帶來了開發的復雜度,這也是需要關注的問題.
功能約束,是架構設計決定性因素.基于游戲領域的功能特征,對服務器端系統來說,有以下幾個特殊的需求:
針對以上的需求特征,在服務器端,我們往往會關注對電腦內存和 CPU 的使用,以求在特定業務代碼下,能盡量滿足承載量和響應延遲的需求.最基本的做法就是“空間換時間”,用各種緩存的方式來以求得 CPU 和內存空間上的平衡.
在 CPU 和內存之上,是另外一個約束因素:網卡.網絡帶寬直接限制了服務器的處理能力,所以游戲服務器架構也必定要考慮這個因素.
對于游戲服務端架構,最重要的三個部分就是,如何使用 CPU、內存、網卡的設計:
服務器基于游戲類型不同,所采用的架構也有所不同,我們先講一下簡單的模型,采用 http 通信模式架構的服務器:
這種服務器架構和我們常用的 web 服務器架構差不多,也是采用 nginx 負載集群支持服務器的水平擴展,memcache 做緩存.唯一不同的地點不同的在于通信層需要對協議再加工和加密,一般每個公司都有自己的一套基于 http 的協議層框架,很少采用開源框架.
長連接游戲和弱聯網游戲不同的地方在于,長連接中,玩家是有狀態的,服務器可以時時和 client 交互,數據的傳送,不像弱聯網一般每次都需要重新創建一個連接,消息傳送的頻率以及速度上都快于弱聯網游戲.
最早的游戲服務器是 1978 年,英國著名的財經學校 University of Essex 的學生 Roy Trubshaw 編寫了世界上第一個 MUD 程序,叫做《MUD1》.《MUD1》程序的源代碼在 ARPANET 共享之后,在全世界廣泛流行起來.不斷完善的 MUD1 的基礎上產生了開源的 MudOS(1991),成為眾多網游的鼻祖.
MUD1 是一款純文字的世界,沒有任何圖片,但是不同計算機前的玩家可以在游戲里共同冒險、交流.與以往具有網絡聯機功能的游戲相比, MUD1 是第一款真正意義上的實時多人交互的網絡游戲,它最大的特色是能夠保證整個虛擬世界和玩家角色的持續發展——無論是玩家退出后重新登錄還是服務器重啟,游戲中的場景、寶箱、怪物和謎題仍保持不變,玩家的角色也依然是上次的狀態.
MUD 中文版
MUDOS 使用單線程無阻塞套接字來服務所有玩家,所有玩家的請求都發到同一個線程去處理,主線程每隔 1 秒鐘更新一次所有對象(網絡收發,對象狀態,刷新地圖,刷新 NPC).用戶使用 Telnet 之類的客戶端用 Tcp 協議連接到 MUDOS 上,使用純文字進行游戲,每條指令用回車進行分割.這樣的系統在當時每臺服務器承載個 4000 人同時游戲.從 1991 年的 MUDOS 發布后,全球各地都在為他改進,擴充,推出新版本.
MUDOS 中游戲內容通過 LPC 腳本進行定制,邏輯處理采用單線程 tick 輪詢,這也是第一款服務端架構模型,后來被應用到不同游戲上.后續很多游戲都是跟《UO》一樣,直接在 MUDOS 上進行二次開發,直到 如今,一些回合制游戲,以及對運算量小的游戲,依然采用這種服務器架構.
第一代服務器架構圖
線程模型
2000 年左右,隨著圖形界面的出現,游戲更多的采用圖形界面與用戶交互.此時隨著在線人數的增加和游戲數據的增加,服務器變得不抗重負.于是就有了分服模型.分服模型結構如下:
分服模型是游戲服務器中最典型,也是歷久最悠久的模型.在早期服務器的承載量達到上限的時候,游戲開發者就通過架設更多的服務器來解決.這樣提供了很多個游戲的“平行世界”,讓游戲中的人人之間的比較,產生了更多的空間.其特征是游戲服務器是一個個單獨的世界.每個服務器的帳號是獨立的,每臺服務器用戶的狀態都是不一樣的,一個服就是一個世界,大家各部牽扯.
后來游戲玩家呼吁要跨服打架,于是出現了跨服戰,再加上隨著游戲的運行,單個服務器的游戲活躍玩家越來越少,所以后期就有了服務器的合并以及遷移,慢慢的以服務器的開放、合并形成了一套成熟的運營手段.目前多數游戲還采用分服的結構來架設服務器,多數頁游還是采用這種模式.
線程調度
分服雖然可以解決服務器擴展的瓶頸,但單臺服務器在以前單線程的方式來運行,沒辦法充分利用服務器資源,于是又演變出了以下兩種線程模型.
異步 – 多線程:基于每個場景(或者房間),分配一個線程.每個場景的玩家同屬于一個線程.游戲的場景是固定的,不會很多,如此線程的數量可以保證不會不斷增大.每個場景線程,同樣采用 tick 輪詢的方式,來定時更新該場景內的(對象狀態,刷新地圖,刷新 NPC)數據狀態.玩家如果跨場景的話,就采用投遞和通知的方式,告知兩個場景線程,以此更新兩個場景的玩家數據.
多進程:由于單進程架構下,總會存在承載量的極限,越是復雜的游戲,其單進程承載量就越低,因此一定要突破進程的限制,才能支撐更復雜的游戲.多進程系統的其他一些好處:能夠利用上多核 CPU 能力、更容易進行容災處理.
多進程系統比較經典的模型是“三層架構”,比如,基于之前的場景線程再做改進,把網絡部分和數據庫部分分離為單獨的進程來處理,邏輯進程專心處理邏輯任務,不合 IO 打交道,網絡 IO 和磁盤 IO 分別交由網路進程和 DB 進程處理.
之前的網游服務器都是分區分服,玩家都被劃分在不同的服務器上,每臺服務器運行的邏輯相同,玩家不能在不同服務器之間交互.想要更多的玩家在同一世界,保持玩家的活躍度,于是就有了世界服模型了.世界服類型也有以下 3 種演化:
一類型(三層架構)
網關部分分離成單端的 gate 服務器,DB 部分分離為 DB 服務器,把網絡功能單獨提取出來,讓用戶統一去連接一個網關服務器,再有網關服務器轉發數據到后端游戲服務器.而游戲服務器之間數據交換也統一連接到網管進行交換.所有有 DB 交互的,都連接到 DB 服務器來代理處理.
二類型(cluster)
有了一類型的經驗,后續肯定是拆分的越細,性能越好,就類似現在微服務,每個相同的模塊分布到一臺服務器處理,多組服務器集群共同組成一個游戲服務端.一般地,我們可以將一個組內的服務器簡單地分成兩類:場景相關的(如:行走、戰斗等)以及場景不相關的(如:公會聊天、不受區域限制的貿易等).經常可以見到的一種方案是:gate 服務器、場景服務器、非場景服務器、聊天管理器、AI 服務器以及數據庫代理服務器.如下模型:
以上中我們簡單的講下服務器的三種類型功能:
通過這種類型服務器架構,因為壓力分散了,性能會有明顯提升,負載也更大了,包括目前一些大型的 MMORPG 游戲就是采用此架構.不過每增加一級服務器,狀態機復雜度可能會翻倍,導致研發和找 bug 的成本上升,這個對開發組挑戰比較大,沒有經驗,很容出錯.
三類型(無縫地圖)
魔獸世界的中無縫地圖,想必大家印象深刻, 整個世界的移動沒有像以往的游戲一樣,在切換場景的時候需要 loading 等待,而是直接行走過去,體驗流暢.
現在的游戲大地圖采用無縫地圖多數采用的是 9 宮格的樣式來處理,由于地圖沒有魔獸世紀那么大,所以采用單臺服務器多進程處理即可,不過類似魔獸世界這種大世界地圖,必須考慮 2 個問題:
1、多個地圖節點如何無縫拼接,特別是當地圖節點比較多的時候,如何保證無縫拼接
2、如何支持動態分布,有些區域人多,有些區域人少,保證服務器資源利用的最大化
為了解決這個問題,比較以往按照地圖來切割游戲而言,無縫世界并不存在一塊地圖上面的人有且只由一臺服務器處理了,此時需要一組服務器來處理,每臺 Node 服務器用來管理一塊地圖區域,由 NodeMaster(NM)來為他們提供總體管理.更高層次的 World 則提供大陸級別的管理服務.
一個 Node 所負責的區域,地理上沒必要連接在一起,可以統一交給一個 Node 去管理,而這些區塊在地理上并沒有聯系在一起的必要性.一個 Node 到底管理哪些區塊,可以根據游戲實時運行的負載情況,定時維護的時候進行更改 NodeMaster 上面的配置.
對象的無縫遷移
玩家 A、B、C 分別代表 3 種不同的狀態,以及不同的遷移方式,我們分別來看.
具體魔獸世界服務器的分析,篇幅過多,我們以后再聊.
房間類玩法和 MMORPG 有很大的不同,在于其在線廣播單元的不確定性和廣播數量很小.而且需要匹配一臺房間服務器讓少數人進入一個服務器.
這一類游戲最重要的是其“游戲大廳”的承載量,每個“游戲房間”受邏輯所限,需要維持和廣播的玩家數據是有限的,但是“游戲大廳”需要維持相當高的在線用戶數,所以一般來說,這種游戲還是需要做“分服”的.典型的游戲就是《英雄聯盟》這一類游戲了.而“游戲大廳”里面最有挑戰性的任務,就是“自動匹配”玩家進入一個“游戲房間”,這需要對所有在線玩家做搜索和過濾.
玩家先登錄“大廳服務器”,然后選擇組隊游戲的功能,服務器會通知參與的所有游戲客戶端,新開一條連接到房間服務器上,這樣所有參與的用戶就能在房間服務器里進行游戲交互了.
以上就是目前游戲服務器的演化進程,由于所涉及的內容太多,關于服務器的相關網絡 IO 以及內存模型都沒有介紹,以后有機會再具體講講這一部分.
wier,樂元素leader軟件工程師.從2010年起從事游戲開發,經歷過頁游和手游兩個游戲發展期,期間曾帶領團隊開發過山寨機上第一款偷菜游戲,如今專注于二次元游戲領域及服務器技術研究,運維了一個游戲公眾號,期待用自己的一點努力和貢獻,推進游戲社區的前進.個人微信號ID:wierWu(添加時請注明‘InfoQ’) ;微信公眾號:大碼侯(cool_wier)
文章來自微信公眾號:高效開發運維