摘要: 本文作為游戲服務(wù)器端開發(fā)的基本大綱,是游戲?qū)嵺`開發(fā)中的總結(jié)。第一部分專業(yè)基礎(chǔ),用于指導(dǎo)招聘和實習(xí)考核, 第二部分游戲入門,講述游戲服務(wù)器端開發(fā)的基本要點,第三部分服務(wù)端架構(gòu),介紹架構(gòu)設(shè)計中的一些基本原則。希望能幫到大家
一 專業(yè)基礎(chǔ)
1.1 網(wǎng)絡(luò)
- 1.1.1 理解TCP/IP協(xié)議
- 網(wǎng)絡(luò)傳輸模型
- 滑動窗口技術(shù)
- 建立連接的三次握手與斷開連接的四次握手
- 連接建立與斷開過程中的各種狀態(tài)
- TCP/IP協(xié)議的傳輸效率
- 思考
- 1)請解釋DOS攻擊與DRDOS攻擊的基本原理
- 2)一個100Byte數(shù)據(jù)包,精簡到50Byte, 其傳輸效率提高了50%
- 3)TIMEWAIT狀態(tài)怎么解釋?
- 1.1.2 掌握常用的網(wǎng)絡(luò)通信模型
- Select
- Epoll,邊緣觸發(fā)與平臺出發(fā)點區(qū)別與應(yīng)用
- Select與Epoll的區(qū)別及應(yīng)用
- 1.2 存儲
- 計算機(jī)系統(tǒng)存儲體系
- 程序運行時的內(nèi)存結(jié)構(gòu)
- 計算機(jī)文件系統(tǒng),頁表結(jié)構(gòu)
- 內(nèi)存池與對象池的實現(xiàn)原理,應(yīng)用場景與區(qū)別
- 關(guān)系數(shù)據(jù)庫MySQL的使用
- 共享內(nèi)存
- 1.3 程序
- 對C/C++語言有較深的理解
- 深刻理解接口,封裝與多態(tài),并且有實踐經(jīng)驗
- 深刻理解常用的數(shù)據(jù)結(jié)構(gòu):數(shù)組,鏈表,二叉樹,哈希表
- 熟悉常用的算法及相關(guān)復(fù)雜度:冒泡排序,快速排序
二 游戲開發(fā)入門
- 2.1防御式編程
- 不要相信客戶端數(shù)據(jù),一定要檢驗。作為服務(wù)器端你無法確定你的客戶端是誰,你也不能假定它是善意的,請做好自我保護(hù)。(這是判斷一個服務(wù)器端程序員是否入門的基本標(biāo)準(zhǔn))
- 務(wù)必對于函數(shù)的傳人參數(shù)和返回值進(jìn)行合法性判斷,內(nèi)部子系統(tǒng),功能模塊之間不要太過信任,要求低耦合,高內(nèi)聚
- 插件式的模塊設(shè)計,模塊功能的健壯性應(yīng)該是內(nèi)建的,盡量減少模塊間耦合
- 2.2 設(shè)計模式
- 道法自然。不要迷信,迷戀設(shè)計模式,更不要生搬硬套
- 簡化,簡化,再簡化,用最簡單的辦法解決問題
- 借大寶一句話:設(shè)計本天成,妙手偶得之
- 2.3 網(wǎng)絡(luò)模型
- 自造輪子: Select, Epoll, Epoll一定比Select高效嗎?
- 開源框架: Libevent, libev, ACE
- 2.4 數(shù)據(jù)持久化
- 自定義文件存儲,如《夢幻西游》
- 關(guān)系數(shù)據(jù)庫: MySQL
- NO-SQL數(shù)據(jù)庫: MongoDB
選擇存儲系統(tǒng)要考慮到因素:穩(wěn)定性,性能,可擴(kuò)展性
- 2.5 內(nèi)存管理
- 使用內(nèi)存池和對象池,禁止運行期間動態(tài)分配內(nèi)存
- 對于輸入輸出的指針參數(shù),嚴(yán)格檢查,寧濫勿缺
- 寫內(nèi)存保護(hù)。使用帶內(nèi)存保護(hù)的函數(shù)(strncpy, memcpy, snprintf, vsnprintf等),嚴(yán)防數(shù)組下標(biāo)越界
- 防止讀內(nèi)存溢出,確保字符串以’\0’結(jié)束
- 2.6 日志系統(tǒng)
- 簡單高效,大量日志操作不應(yīng)該影響程序性能
- 穩(wěn)定,做到服務(wù)器崩潰是日志不丟失
- 完備,玩家關(guān)鍵操作一定要記日志,理想的情況是通過日志能重建任何時刻的玩家數(shù)據(jù)
- 開關(guān),開發(fā)日志的要加級別開關(guān)控制
- 2.7 通信協(xié)議
- 采用PDL(Protocol Design Language), 如Protobuf,可以同時生成前后端代碼,減少前后端協(xié)議聯(lián)調(diào)成本, 擴(kuò)展性好
- JSON,文本協(xié)議,簡單,自解釋,無聯(lián)調(diào)成本,擴(kuò)展性好,也很方便進(jìn)行包過濾以及寫日志
- 自定義二進(jìn)制協(xié)議,精簡,有高效的傳輸性能,完全可控,幾乎無擴(kuò)展性
- 2.8 全局唯一Key(GUID)
- 為合服做準(zhǔn)備
- 方便追蹤道具,裝備流向
- 每個角色,裝備,道具都應(yīng)對應(yīng)有全局唯一Key
- 2.9 多線程與同步
- 消息隊列進(jìn)行同步化處理
- 2.10 狀態(tài)機(jī)
- 強(qiáng)化角色的狀態(tài)
- 前置狀態(tài)的檢查校驗
- 2.11 數(shù)據(jù)包操作
- 合并, 同一幀內(nèi)的數(shù)據(jù)包進(jìn)行合并,減少IO操作次數(shù)
- 單副本, 用一個包盡量只保存一份,減少內(nèi)存復(fù)制次數(shù)
- AOI同步中減少中間過程無用數(shù)據(jù)包
- 2.12 狀態(tài)監(jiān)控
- 隨時監(jiān)控服務(wù)器內(nèi)部狀態(tài)
- 內(nèi)存池,對象池使用情況
- 幀處理時間
- 網(wǎng)絡(luò)IO
- 包處理性能
- 各種業(yè)務(wù)邏輯的處理次數(shù)
- 2.13 包頻率控制
- 基于每個玩家每條協(xié)議的包頻率控制,癱瘓變速齒輪
- 2.14 開關(guān)控制
- 每個模塊都有開關(guān),可以緊急關(guān)閉任何出問題的功能模塊
2.15 反外掛反作弊
- 包頻率控制可以消滅變速齒輪
- 包id自增校驗,可以消滅WPE
- 包校驗碼可以消滅包攔截篡改
- 圖形識別嗎,可以踢掉99%非人的操作
- 魔高一尺,道高一丈
- 2.16 熱更新
- 核心配置邏輯的熱更新,如防沉迷系統(tǒng),包頻率控制,開關(guān)控制等
- 代碼基本熱更新,如Erlang,Lua等
- 2.17 防刷
- 關(guān)鍵系統(tǒng)資源(如元寶,精力值,道具,裝備等)的產(chǎn)出記日志
- 資源的產(chǎn)出和消耗盡量依賴兩個或以上的獨立條件的檢測
- 嚴(yán)格檢查各項操作的前置條件
- 校驗參數(shù)合法性
- 2.18 防崩潰
- 系統(tǒng)底層與具體業(yè)務(wù)邏輯無關(guān),可以用大量的機(jī)器人壓力測試暴露各種bug,確保穩(wěn)定
- 業(yè)務(wù)邏輯建議使用腳本
- 系統(tǒng)性的保證游戲不會崩潰
- 2.19 性能優(yōu)化
- IO操作異步化
- IO操作合并緩寫 (事務(wù)性的提交db操作,包合并,文件日志緩寫)
- Cache機(jī)制
- 減少競態(tài)條件 (避免頻繁進(jìn)出切換,盡量減少鎖定使用,多線程不一定由于單線程) 多線程不一定比單線程快
- 減少內(nèi)存復(fù)制
- 自己測試,用數(shù)據(jù)說話,別猜
- 2.20 運營支持
- 接口支持:實時查詢,控制指令,數(shù)據(jù)監(jiān)控,客服處理等
- 實現(xiàn)考慮提供Http接口
- 2.21 容災(zāi)與故障預(yù)案
- 略
三 服務(wù)器端架構(gòu)
- 3.1 什么是好的架構(gòu)?
- 滿足業(yè)務(wù)要求
- 能迅速的實現(xiàn)策劃需求,響應(yīng)需求變更
- 系統(tǒng)級的穩(wěn)定性保障
- 簡化開發(fā)。將復(fù)雜性控制在架構(gòu)底層,降低對開發(fā)人員的技術(shù)要求,邏輯開發(fā)不依賴于開發(fā)人員本身強(qiáng)大的技術(shù)實力,提高開發(fā)效率
- 完善的運營支撐體系
- 3.2 架構(gòu)實踐的思考
- 簡單,滿足需求的架構(gòu)就是好架構(gòu)
- 設(shè)計性能,抓住重要的20%, 沒必要從程序代碼里面去摳性能
- 熱更新是必須的
- 人難免會犯錯,盡可能的用一套機(jī)制去保障邏輯的健壯性
游戲服務(wù)器的設(shè)計是一項頗有挑戰(zhàn)性的工作,游戲服務(wù)器的發(fā)展也由以前的單服結(jié)構(gòu)轉(zhuǎn)變?yōu)槎喾C(jī)構(gòu),甚至出現(xiàn)了bigworld引擎的分布式解決方案,最近了解到Unreal的服務(wù)器解決方案atlas也是基于集群的方式。
負(fù)載均衡是一個很復(fù)雜的課題,這里暫不談bigworld和atlas的這類服務(wù)器的設(shè)計,更多的是基于功能和場景劃分服務(wù)器結(jié)構(gòu)。
首先說一下思路,服務(wù)器劃分基于以下原則:
- 分離游戲中占用系統(tǒng)資源(cpu,內(nèi)存,IO等)較多的功能,獨立成服務(wù)器。
- 在同一服務(wù)器架構(gòu)下的不同游戲,應(yīng)盡可能的復(fù)用某些服務(wù)器(進(jìn)程級別的復(fù)用)。
- 以多線程并發(fā)的編程方式適應(yīng)多核處理器。
- 寧可在服務(wù)器之間多復(fù)制數(shù)據(jù),也要保持清晰的數(shù)據(jù)流向。
- 主要按照場景劃分進(jìn)程,若需按功能劃分,必須保持整個邏輯足夠的簡單,并滿足以上1,2點。
服務(wù)器結(jié)構(gòu)圖:

各個服務(wù)器的簡要說明:
Gateway 是應(yīng)用網(wǎng)關(guān),主要用于保持和client的連接,該服務(wù)器需要2種IO,對client采用高并發(fā)連接,低吞吐量的網(wǎng)絡(luò)模型,如IOCP等,對服務(wù)器采用高吞吐量連接,如阻塞或異步IO。
網(wǎng)關(guān)主要有以下用途:
- 分擔(dān)了網(wǎng)絡(luò)IO資源
- 同時,也分擔(dān)了網(wǎng)絡(luò)消息包的加解密,壓縮解壓等cpu密集的操作。
- 隔離了client和內(nèi)部服務(wù)器組,對client來說,它只需要知道網(wǎng)關(guān)的相關(guān)信息即可(ip和port)。
- client由于一直和網(wǎng)關(guān)保持常連接,所以切換場景服務(wù)器等操作對client來說是透明的。
- 維護(hù)玩家登錄狀態(tài)。
World Server 是一個控制中心,它負(fù)責(zé)把各種計算資源分布到各個服務(wù)器,它具有以下職責(zé):
- 管理和維護(hù)多個Scene Server。
- 管理和維護(hù)多個功能服務(wù)器,主要是同步數(shù)據(jù)到功能服務(wù)器。
- 復(fù)雜轉(zhuǎn)發(fā)其他服務(wù)器和Gateway之間的數(shù)據(jù)。
- 實現(xiàn)其他需要跨場景的功能,如組隊,聊天,幫派等。
Phys Server 主要用于玩家移動,碰撞等檢測。
所有玩家的移動類操作都在該服務(wù)器上做檢查,所以該服務(wù)器本身具備所有地圖的地形等相關(guān)信息。具體檢查過程是這樣的:首先,Worldserver收到一個移動信息,WorldServer收到后向Phys Server請求檢查,Phys Server檢查成功后再返回給world Server,然后world server傳遞給相應(yīng)的Scene Server。
Scene Server 場景服務(wù)器,按場景劃分,每個服務(wù)器負(fù)責(zé)的場景應(yīng)該是可以配置的。理想情況下是可以動態(tài)調(diào)節(jié)的。
ItemMgr Server 物品管理服務(wù)器,負(fù)責(zé)所有物品的生產(chǎn)過程。在該服務(wù)器上存儲一個物品掉落數(shù)據(jù)庫,服務(wù)器初始化的時候載入到內(nèi)存。任何需要產(chǎn)生物品的服務(wù)器均與該服務(wù)器直接通信。
AIServer 又一個功能服務(wù)器,負(fù)責(zé)管理所有NPC的AI。AI服務(wù)器通常有2個輸入,一個是Scene Server發(fā)送過來的玩家相關(guān)操作信息,另一個時鐘Timer驅(qū)動,在這個設(shè)計中,對其他服務(wù)器來說,AIServer就是一個擁有很多個NPC的客戶端。AIserver需要同步所有與AI相關(guān)的數(shù)據(jù),包括很多玩家數(shù)據(jù)。由于AIServer的Timer驅(qū)動特性,可在很大程度上使用TBB程序庫來發(fā)揮多核的性能。
把網(wǎng)絡(luò)游戲服務(wù)器分拆成多個進(jìn)程,分開部署。這種設(shè)計的好處是模塊自然分離,可以單獨設(shè)計。分擔(dān)負(fù)荷,可以提高整個系統(tǒng)的承載能力。
缺點在于,網(wǎng)絡(luò)環(huán)境并不那么可靠。跨進(jìn)程通訊有一定的不可預(yù)知性。服務(wù)器間通訊往往難以架設(shè)調(diào)試環(huán)境,并很容易把事情攪成一團(tuán)糨糊。而且正確高效的管理多連接,對程序員來說也是一項挑戰(zhàn)。
前些年,我也曾寫過好幾篇與之相關(guān)的設(shè)計。這幾天在思考一個問題:如果我們要做一個底層通用模塊,讓后續(xù)開發(fā)更為方便。到底要解決怎樣的需求。這個需求應(yīng)該是單一且基礎(chǔ)的,每個應(yīng)用都需要的。
正如 TCP 協(xié)議解決了互聯(lián)網(wǎng)上穩(wěn)定可靠的點對點數(shù)據(jù)流通訊一樣。游戲世界實際需要的是一個穩(wěn)定可靠的在游戲系統(tǒng)內(nèi)的點對點通訊需要。
我們可以在一條 TCP 連接之上做到這一點。一旦實現(xiàn),可以給游戲服務(wù)的開發(fā)帶來極大的方便。
可以把游戲系統(tǒng)內(nèi)的各項服務(wù),包括并不限于登陸,拍賣,戰(zhàn)斗場景,數(shù)據(jù)服務(wù),等等獨立服務(wù)看成網(wǎng)絡(luò)上的若干終端。每個玩家也可以是一個獨立終端。它們一起構(gòu)成一個網(wǎng)絡(luò)。在這個網(wǎng)絡(luò)之上,終端之間可以進(jìn)行可靠的連接和通訊。
實現(xiàn)可以是這樣的:每個虛擬終端都在游戲虛擬網(wǎng)絡(luò)(Game Network)上有一個唯一地址 (Game Network Address , GNA) 。這個地址可以預(yù)先設(shè)定,也可以動態(tài)分配。每個終端都可以通過游戲網(wǎng)絡(luò)的若干接入點 ( GNAP ) 通過唯一一條 TCP 連接接入網(wǎng)絡(luò)。接入過程需要通過鑒權(quán)。
鑒權(quán)過程依賴內(nèi)部的安全機(jī)制,可以包括密碼證書,或是特別的接入點區(qū)分。(例如,玩家接入網(wǎng)絡(luò)就需要特定的接入點,這個接入點接入的終端都一定是玩家)
鑒權(quán)通過后,網(wǎng)絡(luò)為終端分配一個固定的游戲域名。例如,玩家進(jìn)入會分配到 player.12345 這樣的域名,數(shù)據(jù)庫接入可能分配到 database 。
游戲網(wǎng)絡(luò)默認(rèn)提供一個域名查詢服務(wù)(這個服務(wù)可以通過鑒權(quán)的過程注冊到網(wǎng)絡(luò)中),讓每個終端都能通過域名查詢到對應(yīng)的地址。
然后,游戲網(wǎng)絡(luò)里所有合法接入的終端都可以通過其地址相互發(fā)起連接并通訊了。整個協(xié)議建立在 TCP 協(xié)議之上,工作于唯一的這個 TCP 連接上。和直接使用 TCP 連接不同。游戲網(wǎng)絡(luò)中每個終端之間相互發(fā)起連接都是可靠的。不僅玩家可以向某個服務(wù)發(fā)起連接,反過來也是可以的。玩家之間的直接連接也是可行的(是否允許這樣,取決于具體設(shè)計)。
由于每個虛擬連接都是建立在單一的 TCP 連接之上。所以減少了互連網(wǎng)上發(fā)起 TCP 連接的各種不可靠性。鑒權(quán)過程也是一次性唯一的。并且我們提供域名反查服務(wù),我們的游戲服務(wù)可以清楚且安全的知道連接過來的是誰。
系統(tǒng)可以設(shè)計為,游戲網(wǎng)絡(luò)上每個終端離網(wǎng),域名服務(wù)將廣播這條消息,通知所有人。這種廣播服務(wù)在互聯(lián)網(wǎng)上難以做到,但無論是廣播還是組播,在這個虛擬游戲網(wǎng)絡(luò)中都是可行的。
在這種設(shè)計上。在邏輯層面,我們可以讓玩家直接把聊天信息從玩家客互端發(fā)送到聊天服務(wù)器,而不需要建立多余的 TCP 連接,也不需要對轉(zhuǎn)發(fā)處理聊天消息做多余的處理。聊天服務(wù)器可以獨立的存在于游戲網(wǎng)絡(luò)。也可以讓廣播服務(wù)主動向玩家推送消息,由服務(wù)器向玩家發(fā)起連接,而不是所有連接請求都是由玩家客互端發(fā)起。
虛擬游戲網(wǎng)絡(luò)的構(gòu)成是一個獨立的層次,完全可以撇開具體游戲邏輯來實現(xiàn),并能夠單獨去按承載量考慮具體設(shè)計方案。非常利于剝離出具體游戲項目來開發(fā)并優(yōu)化。
最終,我們或許需要的一套 C 庫,用于游戲網(wǎng)絡(luò)內(nèi)的通訊。api 可以和 socket api 類似。額外多兩條接入與離開游戲網(wǎng)絡(luò)即可。
posted on 2017-04-07 10:32
思月行云 閱讀(411)
評論(0) 編輯 收藏 引用 所屬分類:
MMO