遊戲服務端架構發展史(上)

skywind發表於2015-07-29

型別1:卡牌,跑酷等弱互動服務端

卡牌跑酷類因為互動弱,玩家和玩家之間不需要實時面對面PK,打一下對方的離線資料,計算下排行榜,買賣下道具即可,所以實現往往使用簡單的 HTTP伺服器:

登入時可以使用非對稱加密(RSA, DH),伺服器根據客戶端uid,當前時間戳還有服務端私鑰,計算雜湊得到的加密 key 併傳送給客戶端。之後雙方都用 HTTP通訊,並用那個key進行RC4加密。客戶端收到key和時間戳後儲存在記憶體,用於之後通訊,服務端不需要儲存 key,因為每次都可以根據客戶端傳上來的 uid 和 時間戳 以及服務端自己的私鑰計算得到。用模仿 TLS的行為,來保證多次 HTTP請求間的客戶端身份,並通過時間戳保證同一人兩次登入金鑰不同。

每局開始時,訪問一下,請求一下關卡資料,玩完了又提交一下,驗算一下是否合法,獲得什麼獎勵,資料庫用單臺 MySQL或者 MongoDB即可,後端的 Redis做快取(可選)。如果要實現通知,那麼讓客戶端定時15秒輪詢一下伺服器,如果有訊息就取下來,如果沒訊息可以逐步放長輪詢時間,比如30秒;如果有訊息,就縮短輪詢時間到10秒,5秒,即便兩人聊天,延遲也能自適應。

此類伺服器用來實現一款三國類策略或者卡牌及酷跑的遊戲已經綽綽有餘,這類遊戲因為邏輯簡單,玩家之間互動不強,使用 HTTP來開發的話,開發速度快,除錯只需要一個瀏覽器就可以把邏輯除錯清楚了。

型別2:第一代遊戲伺服器 1978

1978年,英國著名的財經學校University of Essex的學生 Roy Trubshaw編寫了世界上第一個MUD程式《MUD1》,在University of Essex於1980年接入 ARPANET之後加入了不少外部的玩家,甚至包括國外的玩家。《MUD1》程式的原始碼在 ARPANET共享之後出現了眾多的改編版本,至此MUD才在全世界廣泛流行起來。不斷完善的 MUD1的基礎上產生了開源的 MudOS(1991),成為眾多網遊的鼻祖:

MUDOS採用 C語言開發,因為玩家和玩家之間有比較強的互動(聊天,交易,PK),MUDOS使用單執行緒無阻塞套接字來服務所有玩家,所有玩家的請求都發到同一個執行緒去處理,主執行緒每隔1秒鐘更新一次所有物件(網路收發,更新物件狀態機,處理超時,重新整理地圖,重新整理NPC)。

遊戲世界採用房間的形式組織起來,每個房間有東南西北四個方向可以移動到下一個房間,由於歐美最早的網遊都是地牢迷宮形式的,因此場景的基本單位被成為 “房間”。MUDOS使用一門稱為LPC的指令碼語言來描述整個世界(包括房間拓撲,配置,NPC,以及各種劇情)。遊戲裡面的高階玩家(巫師),可以不斷的通過修改指令碼來為遊戲新增房間以及增加劇情。早年 MUD1上線時只有17個房間,Roy Trubshaw畢業以後交給他的師弟 Richard Battle,在 Richard Battle手上,不斷的新增各種玩法到一百多個房間,終於讓 MUD發揚光大。

使用者使用 Telnet之類的客戶端用 Tcp協議連線到 MUDOS上,使用純文字進行遊戲,每條指令用回車進行分割。比如 1995年國內第一款 MUD遊戲《俠客行》,你敲入:”go east”,遊戲就會提示你:“後花園 – 這裡是歸雲莊的後花園,種滿了花草,幾個莊丁正在澆花。此地乃是含羞草生長之地。這裡唯一的出口是 north。這裡有:花待 阿牧(A mu),還有二位莊丁(Zhuang Ding)”,然後你繼續用文字操作,檢視阿牧的資訊:“look a mu”,系統提示:“花待 阿牧(A mu)他是陸乘風的弟子,受命在此看管含羞草。他看起來三十多歲,生得眉清目秀,端正大方,一表人才。他的武藝看上去【不是很高】,出手似乎【極輕】”。然後你可以選擇擊敗他獲得含羞草,但是你吃了含羞草卻又可能會中毒死亡。在早期網上資源貧乏的時候,這樣的遊戲有很強的代入感。

使用者資料儲存在檔案中,每個使用者登入時,從文字檔案裡把使用者的資料全部載入進來,操作全部在記憶體裡面進行,無需馬上刷回磁碟。使用者退出了,或者每隔5分鐘檢查到資料改動了,都會儲存會磁碟。這樣的系統在當時每臺伺服器承載個4000人同時遊戲,不是特別大的問題。從1991年的 MUDOS釋出後,全球各地都在為他改進,擴充,退出新版本,隨著 Windows圖形機能的增強。1997遊戲《UO》在 MUDOS的基礎上為角色增加的x,y座標,為每個房間增加了地圖,並且為每個角色增加了動畫,形成了第一代的圖形網路遊戲。

因為遊戲內容基本可以通過 LPC指令碼進行定製,所以MUDOS也成為名副其實的第一款服務端引擎,引擎一次性開發出來,然後製作不同遊戲內容。後續國內的《萬王之王》等遊戲,很多都是跟《UO》一樣,直接在 MUDOS上進行二次開發,加入房間的地圖還有角色的座標等要素,該架構一直為國內的第一代 MMORPG提供了穩固的支援,直到 2003年,還有遊戲基於 MUDOS開發。

雖然後面圖形化增加了很多東西,但是這些MMORPG後端的本質還是 MUDOS。隨著遊戲內容的越來越複雜,架構變得越來越吃不消了,各種負載問題慢慢浮上水面,於是有了我們的第二代遊戲伺服器。

型別3:第二代遊戲伺服器 2003

2000年後,網遊已經脫離最初的文字MUD,進入全面圖形化年代。最先承受不住的其實是很多小檔案,使用者上下線,頻繁的讀取寫入使用者資料,導致負載越來越大。隨著線上人數的增加和遊戲資料的增加,伺服器變得不抗重負。同時早期 EXT磁碟分割槽比較脆弱,稍微停電,容易發生大面積資料丟失。因此第一步就是拆分檔案儲存到資料庫去:

此時遊戲服務端已經脫離陳舊的 MUDOS體系,各個公司在參考 MUDOS結構的情況下,開始自己用 C在重新開發自己的遊戲服務端。並且指令碼也拋棄了 LPC,採用擴充套件性更好的 Python或者 Lua來代替。由於主邏輯使用單執行緒模型,隨著遊戲內容的增加,傳統單伺服器的結構進一步成為瓶頸。於是有人開始拆分遊戲世界,變為下面的模型:

遊戲伺服器壓力拆分後得意緩解,但是兩臺遊戲伺服器同時訪問資料庫,大量重複訪問,大量資料交換,使得資料庫成為下一個瓶頸。於是形成了資料庫前端代理(DB Proxy),遊戲伺服器不直接訪問資料庫而是訪問代理,再有代理訪問資料庫,同時提供記憶體級別的cache。早年 MySQL4之前沒有提供儲存過程,這個前端代理一般和 MySQL跑在同一臺上,它轉化遊戲伺服器發過來的高階資料操作指令,拆分成具體的資料庫操作,一定程度上代替了儲存過程:

但是這樣的結構並沒有持續太長時間,因為玩家切換場景經常要切換連線,中間的狀態容易錯亂。而且遊戲伺服器多了以後,相互之間資料互動又會變得比較麻煩,於是人們拆分了網路功能,獨立出一個閘道器服務 Gate(有的地方叫 Session,有的地方叫 LinkSvr之類的,名字不同而已):

但是這樣的結構並沒有持續太長時間,因為玩家切換場景經常要切換連線,中間的狀態容易錯亂。而且遊戲伺服器多了以後,相互之間資料互動又會變得比較麻煩,於是人們拆分了網路功能,獨立出一個閘道器服務 Gate(有的地方叫 Session,有的地方叫 LinkSvr之類的,名字不同而已):

把網路功能單獨提取出來,讓使用者統一去連線一個閘道器伺服器,再有閘道器伺服器轉發資料到後端遊戲伺服器。而遊戲伺服器之間資料交換也統一連線到網管進行交換。這樣型別的伺服器基本能穩定的為玩家提供遊戲服務,一臺閘道器服務1-2萬人,後面的遊戲伺服器每臺服務5k-1w,依遊戲型別和複雜度不同而已,圖中隱藏了很多不重要的伺服器,如登入和管理。這是目前應用最廣的一個模型,到今天任然很多新專案會才用這樣的結構來搭建。

人都是有慣性的,按照先前的經驗,似乎把 MUDOS拆分的越開效能越好。於是大家繼續想,閘道器可以拆分呀,基礎服務如聊天交易,可以拆分呀,還可以提供web介面,資料庫可以拆分呀,於是有了下面的模型:

這樣的模型好用麼?確實有成功遊戲使用類似這樣的架構,並且發揮了它的效能優勢,比如一些大型 MMORPG。但是有兩個挑戰:每增加一級伺服器,狀態機複雜度可能會翻倍,導致研發和找bug的成本上升;並且對開發組挑戰比較大,一旦專案時間吃緊,開發人員經驗不足,很容易弄掛。

比如我見過某上海一線遊戲公司的一個 RPG上來就要上這樣的架構,我看了下他們團隊成員的經驗,問了下他們的上線日期,勸他們用前面稍微簡單一點的模型。人家自信得很,認為有成功專案是這麼做的,他們也要這麼做,自己很想實現一套。於是他們義無反顧的開始編碼,專案做了一年多,然後,就沒有然後了。

現今在遊戲成功率不高的情況下,一開始上一套比較複雜的架構需要考慮投資回報率,比如你的遊戲上線半年內 PCU會去到多少?如果一個 APRG遊戲,每組伺服器5千人都到不了的話,那麼選擇一套更為貼近實際情況的結構更為經濟。即使後面你的專案真的超過5千人朝著1萬人目標奔的話,相信那個時候你的專案已經掙大錢了 ,你數著錢加著班去逐步迭代,一次次拆分它,相信心裡也是樂開花的。

上面這些型別基本都是從拆分 MUDOS開始,將 MUDOS中的各個部件從單機一步步拆成分散式。雖然今天任然很多新專案在用上面某一種類似的結構。因為他們本質上都是對 MUDOS的分解,故將他們歸納為第二代遊戲伺服器。

遊戲服務端架構發展史(中)

相關文章