一、游戲服務器、普通APP和web服務器
如果是同等用戶規模,相對來說,游戲服務器的復雜程度要大于普通app和web服務器。當然涉及到特殊算法的服務器另說,比如搜索引擎、頭條人工智能推薦這些除外,在這里只說普通的。
二、游戲服務器類型
游戲服務器根據不同的游戲類型有很大的區別,如王者榮耀之類的MOBA手游,服務器主要由2部分構成,局內戰斗服務器和局外系統服務器。
局內戰斗服務器程序是游戲專用的,在其他app服務器上幾乎沒有使用場景,在技術方面是有鴻溝的,也就是說你在開發app服務器上使用的技術以及設計思路,是無法轉換為局內戰斗服務器設計思路的,兩者之間存沒有相同點。
二、幀同步和狀態同步
戰斗服務器需要做到給各個玩家數據同步,也就是說,在一局游戲內,所有玩家的實時狀態都要相互可見。這其中又設計到2種技術,幀同步和狀態同步。
幀同步服務器不包含游戲邏輯,就是簡單將客戶端發送過來的命令轉發給其他客戶端,比如玩家A執行一個攻擊操作,那么玩家A客戶端會給服務器發送一個攻擊命令,服務器將這個命令同步給局內的其他玩家,至于攻擊一下少多少點血,會不會把人打死,服務器不管,全部由客戶端完成計算判斷,客戶端計算完畢后將結果發送給服務器,服務器再將結果同步給其他玩家,然后客戶端播放表現效果。簡單的說幀同步服務器就是給各個游戲客戶端同步數據,它會不間斷的發,即使局內的玩家什么都不干,傻傻的站在那里,服務器也會發,他的作用就是同步玩家們的狀態,所以說幀同步服務器費流量。
狀態同步服務器和幀同步服務器的區別在于,除了同步玩家狀態的機制相同外,狀態同步服務器包含游戲的運行邏輯,比如玩家之間互相攻擊、技能傷害大小計算,都在服務器上執行,然后再將執行結果同步給客戶端,客戶端只要根據結果播放對應的動畫就可以了。
簡而言之,幀同步服務器和狀態同步服務器的區別就是游戲局內游戲邏輯放在哪兒運行的問題。因為要運行游戲邏輯,狀態同步非常消耗服務器資源,如果代碼寫的爛一點,一臺4核8G的機器上只能跑10局游戲100個玩家,那么要是同時有10萬玩家在局內,就需要1000臺服務器,這么多服務器,運維管理壓力非常大。因此使用幀同步服務器能有效的減少服務器消耗資源,減少服務器數量。然而有缺點就有優點,因為業務邏輯在客戶端,幀同步服務器很難有效的杜絕外掛問題,斷線重連也相對費勁,用戶體驗差。而狀態同步則不存在這種問題,能有效的杜絕外掛,也能很容易的支持重連進入游戲。所以這兩種技術各有優缺點,選擇哪一種,需要根據實際情況權衡。
四、TCP與UDP協議
普通的web服務器或者app服務器十有八九使用基于tcp的http協議,而局內戰斗服務器,普遍使用UDP。TCP是可靠傳輸協議,用起來省事,確認機制、丟包重傳、滑動窗口之類機制開銷也大,在極端性能敏感的場景下,裸奔的UDP更加合適,通過UDP實現一個lite版的TCP,是游戲戰斗服務器常規的優化手段。
不過話說回來,看起來局內戰斗服務器實現有很多門道,但是工作量其實非常少,屬于做好一次到處通用, 即使狀態同步,雖然業務邏輯跑在服務器上,但實際功能開發還是客戶端程序員實現,服務器只是提供了一個運行程序的容器,戰斗邏輯的實現不歸服務器管。
再說說局外服務器,這部分和普通的web服務器和app服務器就比較像了,MySql、Redis、protobuf、消息隊列、分布式框架等等互聯網應用的基礎架構在游戲服務器上也是常規配置,不過有一點明顯的區別是,游戲服務器的數據存儲都是以玩家為單位的,當玩家登錄的時候,程序會將所有玩家的數據,如道具、裝備、任務等所有相關數據從MySql等數據庫中加載到程序內存,之后所有的操作都在內存中進行,之后等到某個適當的時機才會將內存中的數據同步到MySql中。當然,為了保證即使程序掛掉,數據也不丟失,還需要設計許多復雜的機制,這里就不展開了。
而web服務器和app服務器則不是這么設計的,因為游戲如果不登錄是不可以玩的,因此我們可以把數據結構設計成以用戶分組的。而web和app即使用戶不登錄,功能依然需要可以使用,功能和用戶不綁定,所以設計的時候也不會把數據以用戶為單位進行組織。不過除了數據組織方式不同外, 其他地方大致都相同,原本是做游戲服務器的,稍微熟悉下就可以去做web或者app服務器,反過來也一樣,互相之間沒有門檻。
不過從技術的角度出發,局外游戲服務器的技術相對與其他互聯網行業是比較落后的,如果你原本是在傳統互聯網行業,轉去做游戲服務器,可能會被雷到,因為他們用的框架一點也不”現代化“,也許框架的性能還不錯, 但是開發效率極低。這一點和游戲客戶端不一樣,游戲客戶端是脫離傳統互聯網技術的,他們有自己的技術棧,而且實時更新。比如unity、unreal引擎出新版本了,他們都會討論的熱火朝天,然后嘗試升級使用,這和互聯網行業的vue、react、spring更新一樣,相關程序員都會熱衷與研究。
但是服務器卻沒有這樣的熱點可以追,我在一家公司,這家公司雖然已經生產了幾十個游戲,客戶端引擎也不知道換了多少套,但是服務器程序卻一點沒變,仍舊使用祖宗流傳下來的那套c++框架,里面什么都是手動實現的
比如數據傳輸協議,是自己組裝字節流,發送給另一端,另一端根據事先定義好的規則,一個int,一個bool,一個float的讀取。這對于理解網絡的本質非常有好處,但是顯然在實際應用中,使用protobuf會更好。
當然我也碰到過協議不自己實現而是使用protobuf的,而且使用的是java開發局外服務器,而網絡底層仍舊使用java自帶的NIO,而不是更好的netty。
總而言之,傳統的游戲服務器程序不是太喜歡用框架,而是偏向于自己造輪子。這可能跟這個行業大量使用c++有關系,即使有一部分游戲使用java服務器 ,但是開發人員大多也是c++轉過來的,還是以c++一切靠自己的思路在開發,所以很難見到流行的互聯網框架在游戲服務器上使用。
游戲服務器不會只用一種語言開發,也可能是兩種。如果是一種,那大概率是c++。如果是兩種,那大概率是c++加另一種語言。
用c++的原因很多,如果要找一種語言,兼顧性能、開發效率、流行度,那肯定是c++。戰斗服務器通常用c++開發,一來是速度夠快;二來戰斗程序通常需要同時在客戶端和服務器上運行,要找一種跨平臺的,還是要c++,比如unity種就可以通過c#調用c++。
局外服務器可以不用c++做,用java、go甚至php都可以,不過近年來用go好像越來越多了。
最后還有一個人員方面的區別,一個傳統互聯網項目,后端開發人員會多于前端開發人員。而一個游戲項目,客戶端開發人員要比服務器開發人員多,可能一個項目服務器程序員只有3個,而客戶端程序員有10多個。而且客戶端程序員都很忙,而服務器程序員,在開發階段,相對很閑,游戲上線后, 會忙一些。