本文並沒有涉及什么逆向工程,只是拜讀刀劍Online服務器端主程的文章后[1],想結合自己的經驗談一談。
PS:由於題目范圍太大,本系列的前言做了一些限制。
一、網絡游戲服務器
要想設計好網絡游戲服務器的構架,首先需要知道網絡游戲服務器在玩家游戲過程中發揮什么作用。就我個人的理解:網游服務器在玩家游戲過程中扮演上帝的角色。玩家在服務器制定的規則下進行游戲,服務器負責同步在線玩家之間的屬性、操作、狀態等等,最終在多個不同的客戶端呈現一個“統一”的游戲世界。
所謂的服務器構架在本系列blog中,主要是指如何將服務器各部分合理的安排,以實現最初的功能需求。好的結構不是一蹴而就的,是通過需求的推動一步步的完善。而且每個設計者心中的標准不盡相同,所以我認為並沒有絕對優秀服務器構架。本系列文章中所謂的優秀構架是指各方面達到一種平衡(包括成本等的非技術因素)。
下面先介紹刀劍Online的服務器構架(后續還可能有WOW、天龍等):
二、刀劍Online
圖1 刀劍Online服務器構架
看了像素的技術總監魏華的文章[1],感覺有點意思。文章中所介紹的服務器構架並不復雜,但滿足一般MMORPG網游要求應該是綽綽有余了。按照魏華自己的話,這樣的服務器構架主要滿足能夠接受以下幾條限制的網絡游戲:
- 游戲同時在線人數在1w人以下。
- 服務器為多進程程序,可部署在一台或者多台機器上。
- 服務器內存足夠大,一般一個進程1~2G的內存需求還是應該滿足的,64位系統能支持更大的內存需求。內存這塊主要看游戲的設計需求。
- 刀劍屬於格斗性質的網游,對CPU和帶寬有一定的要求。(這篇文章寫於2005年,當時刀劍可能是按照256k、512k或1M ADSL的網速進行設計的。現在已經開始普及10M網,帶寬和網速應該可以滿足),網絡延遲的問題本文后面再做展開。對CPU的要求主要影響可承載人數。
- 地圖采用獨立小場景的管理模式,各個場景之間通過傳送點來連接。每個場景服務器程序分管一部分地圖。
服務器包括游戲中和游戲外兩大部分,這里主要討論游戲中的服務器構架,類似客戶端自動更新等的游戲外服務器不在本文的討論范圍。
接下來對刀劍Online的服務器構架的各個部分進行詳細的分析,其中包含很多我自己的想法,很多內容都是我猜測的,因此不能“信以為真”。
2.1 連接負載服務器(Connection Load Server,CLS)
游戲客戶端在游戲過程中實際上是和連接負載服務器(簡稱CLS)進行連接並做數據交互的。如文中[1]所訴,CLS主要的作用是:
- 把網絡連接和真正的游戲邏輯隔離開,降低游戲邏輯服務器處理網絡交互的負擔,同時提高游戲的安全性。有了CLS,刀劍Online的服務器對於玩家來說就是一個黑盒,如下圖:
- 使場景服務器(Zone Server)更為獨立——客戶端連接CLS而不是直接連接Zone Server的好處是:用戶切換場景服務器時,並不會導致原來的TCP連接斷開,從而使設計更為簡單和獨立。
- 提高發送廣播消息的效率,比如需要全服廣播時,游戲邏輯服務器只需要對CLS發送一條廣播指令,而向每個用戶的廣播工作由CLS完成。
- 完成客戶端數據交互的加密解密過程。
連接服務器的主要工作正如上述魏華談到的,但有幾點並沒有做出強調,下面本人結合平時的實際工作給出一些補充(不一定正確):
根據經驗:
CLS作為與client建立連接、進行數據交互的“Gate”,從程序角度來看CLS的代碼應該是最簡潔高效的。因為CLS主要負責與客戶端交互數據是的加密解密、以及數據搬運。而使用流加密算法RC4對整個數據流進行加密解密是很耗CPU的,因此代碼的高效在這個模塊是十分的重要。
為了提高程序的運行效率,CLS程序往往會使用-O3的選項進行編譯,這無形中又對代碼的編寫有更高的要求。CLS一般會有自己的打包機制(控制發送頻率),因此常會使用TCP_NODELAY選項禁用Nagle算法。
CLS常會被分配到不同的物理機器上,因為操作系統在處理TCP包時,需要通過軟中斷來通知進程或者喚醒system call,在服務器十分繁忙的時候CPU可能處理不過來。解決辦法是:使用多核的服務器,然后把TCP的軟中斷平均分配到多個CPU。(一些操作系統默認只使用0號CPU來處理,Fedora Core release 2默認就是只使用0號CPU,較新的版本我沒有做研究)
CLS在做數據流的解密后,往往需要把數據包構造成內部服務器進程間通訊使用的protocol,這種protocol模塊要獨立,序列化和反序列化的接口要穩定,這樣以后需要更換協議模塊也不至於傷筋動骨。可以使用像google的protobuf這樣的開源協議,減少開發難度。
CLS負責建立和client的連接,多會使用多個CLS進程才能支撐1w的在線人數,因此在CLS前端一般會有負載均衡的程序,負責把建立連接的請求均勻的提交到各個CLS。
有一個需要討論的問題:作為服務器端的“Gate”,只負責數據轉發的CLS是否需要對client發過來的數據進行完全的解密?或者只解密包頭,知道轉發的目的地即可?(RC4並沒有增加流的長度,因此可以只做部分解密)
CLS只做部分解密:
好處:將耗費CPU資源的解密功能分攤到別的進程;各進程各服務可以在解密后用不同的方案來構造自己的protocol。
CLS做完全解密:
好處:可以提前過濾部分無效的消息,只做部分解密也可以做提前過濾,但是這樣太過於依賴協議的設計;在CLS處做完全解密,則往后服務器端的之間的消息傳遞都是明文,利於抓包查錯;由於CLS的功能比較簡單,很容易通過加機器來進行擴展,因此計算放在CLS上是比較明智的選擇。
總結:
CLS是一個功能相對簡單但要求代碼簡潔高效的程序,在設計實現的時應該注重效率及代碼編寫規范。經過對比在CLS程序對數據流進行完全解密是利大於弊的,推薦使用這種方案。
2.2 ...................待續
(2.2節及后續章節將寫在后面的文章里)
References:
[1]像素軟件技術總監--魏華:《刀劍Online服務器構架分析》