服務器端開發的一些建議

一 專業基礎

1.1 網絡

1.1.1 理解TCP/IP協議
網絡傳輸模型
滑動窗口技術
創建鏈接的三次握手與斷開鏈接的四次握手
鏈接創建與斷開過程當中的各類狀態
TCP/IP協議的傳輸效率
思考
 
1)請解釋DOS攻擊與DRDOS攻擊的基本原理
2)一個100Byte數據包,精簡到50Byte, 其傳輸效率提升了50%
3)TIMEWAIT狀態怎麼解釋?
1.1.2 掌握經常使用的網絡通訊模型
Select
Epoll,邊緣觸發與平臺出發點區別與應用
Select與Epoll的區別及應用
1.2 存儲
計算機 系統存儲體系
程序運行時的內存結構
計算機文件系統,頁表結構
內存池與對象池的實現原理,應用場景與區別
關係 數據庫MySQL的使用
共享內存
1.3 程序
對C/C++語言有較深的理解
深入理解接口,封裝與多態,而且有實踐經驗
深入理解經常使用的數據結構:數組,鏈表,二叉樹,哈希表
熟悉經常使用的算法及相關複雜度:冒泡排序,快速排序

二 遊戲開發入門

2.1防護式 編程
不要相信客戶端數據,必定要檢驗。做爲服務器端你沒法肯定你的客戶端是誰,你也不能假定它是善意的,請作好自我保護。(這是判斷一個服務器端程序員是否入門的基本標準)
務必對於函數的傳人蔘數和返回值進行合法性判斷,內部子系統,功能模塊之間不要太過信任,要求低耦合,高內聚
插件式的模塊設計,模塊功能的健壯性應該是內建的,儘可能減小模塊間耦合
2.2 設計模式
道法天然。不要迷信,迷戀設計模式,更不要生搬硬套
簡化,簡化,再簡化,用最簡單的辦法解決問題
借大寶一句話:設計本天成,妙手偶得之
2.3 網絡模型
自造輪子: Select, Epoll, Epoll必定比Select高效嗎?
開源框架: Libevent, libev, ACE
2.4 數據持久化
自定義文件存儲,如《夢幻西遊》
關係數據庫: MySQL
NO-SQL數據庫: MongoDB

選擇存儲系統要考慮到因素:穩定性,性能,可擴展性linux

2.5 內存管理
使用內存池和對象池,禁止運行期間動態分配內存
對於輸入輸出的指針參數,嚴格檢查,寧濫勿缺
寫內存保護。使用帶內存保護的函數(strncpy, memcpy, snprintf, vsnprintf等),嚴防數組下標越界
防止讀內存溢出,確保字符串以’\0’結束
2.6 日誌系統
簡單高效,大量日誌操做不該該影響程序性能
穩定,作到服務器崩潰是日誌不丟失
完備,玩家關鍵操做必定要記日誌,理想的狀況是經過日誌能重建任什麼時候刻的玩家數據
開關,開發日誌的要加級別開關控制
2.7 通訊協議
採用PDL(Protocol Design Language), 如Protobuf,能夠同時生成先後端代碼,減小先後端協議聯調成本, 擴展性好
JSON,文本協議,簡單,自解釋,無聯調成本,擴展性好,也很方便進行包過濾以及寫日誌
自定義二進制協議,精簡,有高效的傳輸性能,徹底可控,幾乎無擴展性
2.8 全局惟一Key(GUID)
爲合服作準備
方便追蹤道具,裝備流向
每一個角色,裝備,道具都應對應有全局惟一Key
2.9 多線程與同步
消息隊列進行同步化處理
2.10 狀態機
強化角色的狀態
前置狀態的檢查校驗
2.11 數據包操做
合併, 同一幀內的數據包進行合併,減小IO操做次數
單副本, 用一個包儘可能只保存一份,減小內存複製次數
AOI同步中減小中間過程無用數據包
2.12 狀態監控
隨時監控服務器內部狀態
內存池,對象池使用狀況
幀處理時間
網絡IO
包處理性能
各類業務邏輯的處理次數
2.13 包頻率控制
基於每一個玩家每條協議的包頻率控制,癱瘓變速齒輪
2.14 開關控制
每一個模塊都有開關,能夠緊急關閉任何出問題的功能模塊
2.15 反外掛反做弊
包頻率控制能夠消滅變速齒輪
包id自增校驗,能夠消滅 WPE
包校驗碼能夠消滅包攔截篡改
圖形識別嗎,能夠踢掉99%非人的操做
魔高一尺,道高一丈
2.16 熱更新
核心配置邏輯的熱更新,如防沉迷系統,包頻率控制,開關控制等
代碼基本熱更新,如Erlang,Lua等
2.17 防刷
關鍵系統資源(如元寶,精力值,道具,裝備等)的產出記日誌
資源的產出和消耗盡可能依賴兩個或以上的獨立條件的檢測
嚴格檢查各項操做的前置條件
校驗參數合法性
2.18 防崩潰
系統底層與具體業務邏輯無關,能夠用大量的機器人壓力測試暴露各類bug,確保穩定
業務邏輯建議使用腳本
系統性的保證遊戲不會崩潰
2.19 性能優化
IO操做異步化
IO操做合併緩寫 (事務性的提交db操做,包合併,文件日誌緩寫)
Cache機制
減小競態條件 (避免頻繁進出切換,儘可能減小鎖定使用,多線程不必定因爲單線程) 多線程不必定比單線程快
減小內存複製
本身測試,用數聽說話,別猜
2.20 運營支持
接口支持:實時查詢,控制指令,數據監控,客服處理等
實現考慮提供Http接口
2.21 容災與故障預案

三 服務器端架構

3.1 什麼是好的架構?
知足業務要求
能迅速的實現策劃需求,響應需求變動
系統級的穩定性保障
簡化開發。將複雜性控制在架構底層,下降對開發人員的技術要求,邏輯開發不依賴於開發人員自己強大的技術實力,提升開發效率
完善的運營支撐體系
3.2 架構實踐的思考
簡單,知足需求的架構就是好架構
設計性能,抓住重要的20%, 不必從程序代碼裏面去摳性能
熱更新是必須的
人不免會犯錯,儘量的用一套機制去保障邏輯的健壯性

遊戲服務器的設計是一項很有挑戰性的工做,遊戲服務器的發展也由之前的單服結構轉變爲多服機構,甚至出現了bigworld引擎的分佈式解決方案,最近了解到Unreal的服務器解決方案atlas也是基於集羣的方式。程序員

負載均衡是一個很複雜的課題,這裏暫不談bigworld和atlas的這類服務器的設計,更多的是基於功能和場景劃分服務器結構。算法

首先說一下思路,服務器劃分基於如下原則:數據庫

  1. 分離遊戲中佔用系統資源(cpu,內存,IO等)較多的功能,獨立成服務器。
  2. 在同一服務器架構下的不一樣遊戲,應儘量的複用某些服務器(進程級別的複用)。
  3. 以多線程併發的編程方式適應多核處理器。
  4. 寧肯在服務器之間多複製數據,也要保持清晰的數據流向。
  5. 主要按照場景劃分進程,若需按功能劃分,必須保持整個邏輯足夠的簡單,並知足以上1,2點。

服務器結構圖:編程

  各個服務器的簡要說明:後端

  Gateway 是應用網關,主要用於保持和client的鏈接,該服務器須要2種IO,對client採用高併發鏈接,低吞吐量的網絡模型,如IOCP等,對服務器採用高吞吐量鏈接,如阻塞或異步IO。設計模式

  網關主要有如下用途:api

  1. 分擔了網絡IO資源
  2. 同時,也分擔了網絡消息包的加解密,壓縮解壓等cpu密集的操做。
  3. 隔離了client和內部服務器組,對client來講,它只須要知道網關的相關信息便可(ip和port)。
  4. client因爲一直和網關保持常鏈接,因此切換場景服務器等操做對client來講是透明的。
  5. 維護玩家登陸狀態。

  World Server 是一個控制中心,它負責把各類計算資源分佈到各個服務器,它具備如下職責:數組

  1. 管理和維護多個Scene Server。
  2. 管理和維護多個功能服務器,主要是同步數據到功能服務器。
  3. 複雜轉發其餘服務器和Gateway之間的數據。
  4. 實現其餘須要跨場景的功能,如組隊,聊天,幫派等。

  Phys Server 主要用於玩家移動,碰撞等檢測。安全

  全部玩家的移動類操做都在該服務器上作檢查,因此該服務器自己具有全部地圖的地形等相關信息。具體檢查過程是這樣的:首先,Worldserver收到一個移動信息,WorldServer收到後向Phys Server請求檢查,Phys Server檢查成功後再返回給world Server,而後world server傳遞給相應的Scene Server。

  Scene Server 場景服務器,按場景劃分,每一個服務器負責的場景應該是能夠配置的。理想狀況下是能夠動態調節的。

  ItemMgr Server 物品管理服務器,負責全部物品的生產過程。在該服務器上存儲一個物品掉落數據庫,服務器初始化的時候載入到內存。任何須要產生物品的服務器均與該服務器直接通訊。

  AIServer 又一個功能服務器,負責管理全部NPC的AI。AI服務器一般有2個輸入,一個是Scene Server發送過來的玩家相關操做信息,另外一個時鐘Timer驅動,在這個設計中,對其餘服務器來講,AIServer就是一個擁有不少個NPC的客戶端。AIserver須要同步全部與AI相關的數據,包括不少玩家數據。因爲AIServer的Timer驅動特性,可在很大程度上使用TBB程序庫來發揮多核的性能。

  把網絡遊戲服務器分拆成多個進程,分開部署。這種設計的好處是模塊天然分離,能夠單獨設計。分擔負荷,能夠提升整個系統的承載能力。

  缺點在於,網絡環境並不那麼可靠。跨進程通信有必定的不可預知性。服務器間通信每每難以架設調試環境,並很容易把事情攪成一團糨糊。並且正確高效的管理多鏈接,對程序員來講也是一項挑戰。

  前些年,我也曾寫過好幾篇與之相關的設計。這幾天在思考一個問題:若是咱們要作一個底層通用模塊,讓後續開發更爲方便。到底要解決怎樣的需求。這個需求應該是單一且基礎的,每一個應用都須要的。

  正如 TCP 協議解決了互聯網上穩定可靠的點對點數據流通信同樣。遊戲世界實際須要的是一個穩定可靠的在遊戲系統內的點對點通信須要。

  咱們能夠在一條 TCP 鏈接之上作到這一點。一旦實現,能夠給遊戲服務的開發帶來極大的方便。

  能夠把遊戲系統內的各項服務,包括並不限於登錄,拍賣,戰鬥場景,數據服務,等等獨立服務當作網絡上的若干終端。每一個玩家也能夠是一個獨立終端。它們一塊兒構成一個網絡。在這個網絡之上,終端之間能夠進行可靠的鏈接和通信。

  實現能夠是這樣的:每一個虛擬終端都在遊戲虛擬網絡(Game Network)上有一個惟一地址 (Game Network Address , GNA) 。這個地址能夠預先設定,也能夠動態分配。每一個終端均可以經過遊戲網絡的若干接入點 ( GNAP ) 經過惟一一條 TCP 鏈接接入網絡。接入過程須要經過鑑權。

  鑑權過程依賴內部的安全機制,能夠包括密碼證書,或是特別的接入點區分。(例如,玩家接入網絡就須要特定的接入點,這個接入點接入的終端都必定是玩家)

  鑑權經過後,網絡爲終端分配一個固定的遊戲域名。例如,玩家進入會分配到 player.12345 這樣的域名,數據庫接入可能分配到 database 。

  遊戲網絡默認提供一個域名查詢服務(這個服務能夠經過鑑權的過程註冊到網絡中),讓每一個終端都能經過域名查詢到對應的地址。

  而後,遊戲網絡裏全部合法接入的終端均可以經過其地址相互發起鏈接並通信了。整個協議創建在 TCP 協議之上,工做於惟一的這個 TCP 鏈接上。和直接使用 TCP 鏈接不一樣。遊戲網絡中每一個終端之間相互發起鏈接都是可靠的。不只玩家能夠向某個服務發起鏈接,反過來也是能夠的。玩家之間的直接鏈接也是可行的(是否容許這樣,取決於具體設計)。

  因爲每一個虛擬鏈接都是創建在單一的 TCP 鏈接之上。因此減小了互連網上發起 TCP 鏈接的各類不可靠性。鑑權過程也是一次性惟一的。而且咱們提供域名反查服務,咱們的遊戲服務能夠清楚且安全的知道鏈接過來的是誰。

系統能夠設計爲,遊戲網絡上每一個終端離網,域名服務將廣播這條消息,通知全部人。這種廣播服務在互聯網上難以作到,但不管是廣播仍是組播,在這個虛擬遊戲網絡中都是可行的。

  在這種設計上。在邏輯層面,咱們可讓玩家直接把聊天信息從玩家客互端發送到聊天服務器,而不須要創建多餘的 TCP 鏈接,也不須要對轉發處理聊天消息作多餘的處理。聊天服務器能夠獨立的存在於遊戲網絡。也可讓廣播服務主動向玩家推送消息,由服務器向玩家發起鏈接,而不是全部鏈接請求都是由玩家客互端發起。

  虛擬遊戲網絡的構成是一個獨立的層次,徹底能夠撇開具體遊戲邏輯來實現,並可以單獨去按承載量考慮具體設計方案。很是利於剝離出具體遊戲項目來開發並優化。

  最終,咱們或許須要的一套 C 庫,用於遊戲網絡內的通信。api 能夠和 socket api 相似。額外多兩條接入與離開遊戲網絡便可。

相關文章
相關標籤/搜索