如何避免遊戲炸服——遊戲上線的RoadMap

水風發表於2023-03-08
如何避免遊戲炸服——遊戲上線的RoadMap

本文是伺服器架構相關的第三篇文章,前兩篇文章:

某百萬DAU遊戲的服務端最佳化工作
遊戲服務端的高併發和高可用

本文我想寫一下,一款遊戲上線前需要做哪些事情,以保證專案上線後的穩定性。若你們公司之前沒有大DAU遊戲上線和運維經驗,現在準備上線一款新遊戲,可以按照這個RoadMap去做或者檢查一遍自己遊戲的上線準備工作。

本文不會寫具體的操作,只是提供一個RoadMap,具體如何做大家可以參考前兩篇文章或者自行查詢相關文件。

所有的工作,都會存在一個工作量和收益的權衡。一般來說,對於大部分遊戲,不需要做到100w以上的同時線上,也不需要做到100%的可用性。具體工作做到哪一步,專案根據自己的情況權衡即可,我在文中會介紹需要重點關注的地方。

這些工作,至少需要提前6個月以上的時間準備,一個資深服務端+一個靠譜執行服務端。

一、遊戲伺服器架構

1.1 選擇適合自己專案和團隊的的伺服器架構

遊戲行業的伺服器架構真的是百花齊放,啥方案都有。傳統的MMO(逆水寒)和最年來常見的開房間遊戲(王者榮耀)的關注重點和技術方案也不一樣了。

設計遊戲伺服器架構時,所有的技術方案都不是一個選擇題,沒有說哪種一定是好的,哪種一定是不好的。(我很討厭脫離業務背景討論技術方案優劣的事情)

若團隊專業,人力充足,可以不考慮架構的複雜性,微服務、K8S等技術用起來,可以做到網際網路級別的水平擴充套件和高併發高可用。這個思路會導致寫程式碼比較複雜,帶來很大的工作量和人力需求,做的好上限很高,做的差下限很低。

但是若團隊較小,經驗也不多,建議不要選特別複雜的架構,儘量讓架構優雅、簡單。儘量不要用各種網際網路的各種新技術,也沒必要追求百萬級的同時線上和高階別的可用性。

這裡推薦一下Skynet,很穩。下限夠高,上限也夠高。

1.2 支援水平擴充套件的架構

從伺服器架構上來看,對於主要邏輯,一定要支援水平擴充套件。遊戲上線後大量玩家湧入,第一個考驗就是,伺服器能否承載這麼多玩家。

比如一款moba或者吃雞這種遊戲,他的主要邏輯是大廳和戰鬥,那麼對於大廳和戰鬥就一定要支援水平擴充套件。而對於登入、匹配這種非主要邏輯,是否支援水平擴充套件是可選項(雖然也不難)。

但是,不支援水平擴充套件的邏輯單點,往往就是遊戲承載上限的瓶頸。找到成為承載瓶頸的單點,並且把他們改造為支援水平擴充套件,是提升遊戲伺服器承載量的主要方法。大家可以根據自己專案的人力、遊戲預期玩家量、遊戲伺服器部署方式等方面進行權衡。

水平擴充套件包括程式級別的,也包括執行緒級別的。對於一個多執行緒的伺服器程式,也儘量不要出現某個執行緒成為瓶頸。這可能會導致這個執行緒跑滿了一個CPU,然後阻塞住了其他執行緒。壓測的時候可以看一下,是否存在某些機器某一個CPU跑滿了,其他CPU還空著。

二、容災

伺服器環境是複雜的,難免機器/程式/網路等出現異常的情況。雖然這種機率較低,但是對於大叢集來說,機器很多,環境複雜,機率就不低了。

2.1 伺服器機器當機

首先考慮遊戲伺服器機器當機的情況,在某些情況下游戲程式被kill也類似於這種情況。

對於這種情況,我們要儘量保證大部分程式被殺死,不會影響到叢集整體的可用性。比如,遊戲中的大廳服和戰鬥服程式被殺死,若只會影響到此程式的玩家和戰鬥,並且玩家和戰鬥能自動的轉移到可用的程式上繼續遊戲,那麼,問題的影響範圍就會小很多。

而對於有些關鍵的程式,比如管理程式,這種程式數量少,且寫容災邏輯的難度更大一些,可以不做容災。

2.2 業務容災

為了做到某些業務節點出現問題時,不會造成整個叢集的不可用,需要在業務層面做一些容災處理。

1)重要模組和高風險模組的解耦

比如,某些單點服務(高風險模組)若出現異常,最好只是這些服務不可用,不要影響到登入(重要模組)。

2)非重要模組可以做到關閉/重啟

有些邊緣服務,比如錄影服,即使出現問題或關閉,也要保證對業務主流程不造成阻塞影響。

3)客戶端、服務端綜合考慮

業務的容災需要從玩家體驗的角度關注,而不只是服務端需要關注的事情。在很多遊戲專案,客戶端服務端是兩個人分開寫的,而考慮業務容災時需要綜合考慮(一般由服務端負責)。

在做業務容災處理的時候,一定要和客戶端一起做,比如,要保證客戶端在登陸時,不會呼叫一些沒有必要的介面。

4)排隊系統

建議所有遊戲都做一個複雜或者簡單的排隊系統,當服務端出現問題時,或者當玩家線上量超過預期時,可以讓玩家去排隊,而不是登陸報錯或卡住無反應。

對於可橫向擴充套件的遊戲,排隊系統不用再的太複雜,因為比較容易提高承載量,只有在出現問題的時候啟用即可;對於傳統MMO這種分割槽遊戲,每個區的承載量是有上限的,這種需要把排隊好好做一下。排隊系統也別搞得太複雜,顯示資訊沒必要特別準確實時,出了bug也蛋疼,參考明日之後百萬陰兵排隊。

2.3 第三方服務異常

遊戲伺服器一般都會使用一些雲廠商提供的Saas服務,比如最常見的資料庫。

一般來說,這些服務是有容災機制的,所以不會出現完全不可用。但是,DB的異常往往會導致網路閃斷,那麼資料庫網路連線的斷線重連,以及在這種情況下如何儘量保證資訊部丟失且保序,就是專案組要做的事情了。

除了網路閃斷,也可能有其他異常情況,比如我們曾遇到資料庫分鐘級別的不可用。大家可以根據自己遊戲使用的服務進行評估。

2.4 容災測試

容災做好了,遊戲上線前要測試一遍,看看在異常情況下, 叢集的表現是否符合預期。

建議對每類服務、每類程式都測試一下不可用時遊戲整個叢集的表現,以及對玩家的遊戲體驗的影響。玩家遊戲體驗要從客戶端的角度評估,才能確認真實環境下的遊戲體驗影響。

此外,在測試的過程中,對於每類故障,也要給出故障恢復手段的建議和演練。比如,是需要重啟整個遊戲伺服器,還是隻需要重啟該程式,還是不需要做任何處理。

三、日誌

伺服器日誌一定要寫的儘量詳細,包括日誌級別、提示資訊、執行狀態等。

不要因為覺得日誌寫多了,會浪費日誌服務的機器成本。只要別輸出完全沒有意義和價值的Debug日誌,以及那種迴圈裡面的海量日誌,日誌多多益善,不然到了線上,會出現“日誌用時方恨少”的情況。

若日誌實在太多,可以在遊戲壓測時觀察一下,一般是因為有太多的無效日誌導致的。

建議使用雲廠商提供的日誌服務,比如,阿里雲日誌服務SLS。AWS沒有類似的服務,我們用的OpenSearch。

四、壓測

壓測不是萬能的,沒有壓測是萬萬不能的。上線前壓測的目的:

  • 驗證架構的承載能力。我個人建議在架構層面要能支援100w的PCU。架構承載和業務承載不是一個東西,某個業務不一定能支撐這麼高的量級,但是當玩家分散到各個玩法後,你的架構要能支撐這個量級。
  • 評估各業務模組的效能表現,關注cpu、記憶體、網路頻寬,對於超出預期的,針對性最佳化。
  • 根據效能資料和硬體指標,為開服資源評估提供資料支撐。
  • 檢查玩家在伺服器高併發情況下的表現。

4.1 壓測框架和壓測指令碼

遊戲伺服器不像web都是用HTTP,所以一般來說,需要自己寫一套自己遊戲伺服器對應的壓測框架或平臺,基於這套框架,可以寫壓測指令碼。

開發完了框架,就可以基於框架寫指令碼了。寫指令碼是一個工作量比較大的工作,最好上線測試前三個月到半年的時間開始寫。寫壓測指令碼就是模擬玩家操作,包括登入、購買物品、升級、匹配、加好友、加幫派、進入戰鬥、戰鬥內的各種操作等等。

一般來說,大廳裡的壓測指令碼比較容易寫,但戰鬥裡面會麻煩一些。不過一般來說,現在常見的開房間類遊戲的玩家上限是有限的,一般不用壓力測試,反而是需要效能測試。傳統的MMO複雜很多。

寫指令碼的時候,儘量模擬玩家的真實操作。比如,測試揹包,可以隔三秒獲得一個物品,然後隔三秒使用一個物品。不要寫成一秒鐘執行100次獲取物品和使用物品的邏輯。

4.2 壓測流程

壓測指令碼寫完了,就可以進行壓測了。

對於壓測承載目標,建議按照策劃/發行評估的同時線上乘以3——5倍的量級進行壓測,或者直接按照100w同時線上去壓測。一方面因為壓測指令碼往往和玩家線上操作有一定的差別,另一方面遊戲也可能超出預期嘛。

壓測過程建議四輪:

  • 小規模壓測:把壓測指令碼和流程跑通,確定框架和壓測指令碼的正確性。
  • 分模組中規模壓測:針對某個系統/功能模組進行壓測,可以定量的分析某個模組的承載量。這種方式可以評估某些單點程式/服務的最大承載量,防止這些單點成為瓶頸。比如登入,可以分析每秒鐘最多能支援多少玩家登入,若QPS太低,可以去找效能瓶頸針對性的最佳化。
  • 大規模壓測:這時候,按照承載目標(100W同時線上)同時上線這麼多玩家,然後隨機或者按照規律把所有的指令碼都跑起來,模擬玩家的各種操作。此外,在大規模壓測期間,也可以用這個叢集作為內部體驗測試叢集,檢查玩家在伺服器高併發情況下的表現。注意,對於小公司,這個壓測時間建議控制在2——3天,,伺服器費用的花費就像燒錢一樣。
  • 線上叢集壓測:上線之前,針對準備用於線上部署的叢集再進行一次整體壓測,按照預期的承載量去壓測,同時確定線上叢集部署的正確性。遊戲開服之前,把資料清檔。


4.3 定位瓶頸

1)架構瓶頸

壓測期間,若沒有達到要求,則要去尋找效能瓶頸。比如登陸的時候,發現登入速度上不去了,就去找問題出在哪裡。是資料庫的問題,還是某個邏輯節點已經跑滿了一個CPU核心。

2)程式碼效能瓶頸

壓測的時候,也可以透過Profile工具,去找到邏輯中的效能熱點,針對性的對程式碼進行效能最佳化。

4.4 周邊服務壓測

除了遊戲業務本身需要壓測,遊戲業務使用的周邊業務,也要進行壓測。比如賬號平臺、支付平臺,或者自己部署的日誌服務等。

若使用了第三方Saas服務,有些可以自己壓測一下,比如DB;有些可以跟第三方明確自己遊戲可能達到的量級,讓他們做好準備。

五、熱更

要保證盡絕大部分程式碼可以支援熱更或者滾動更新。

遊戲上線後,不可能沒有bug,也不可能透過重啟伺服器來修復bug。

要做好熱更流程的演練和測試,對於各類模組和服務,都要測試一下熱更是正確的。

六、資料庫相關

6.1 資料庫選型

遊戲伺服器常用的資料庫包括:Mysql、Mongo、Redis。選擇合適的並且自己團隊熟悉的資料庫。

建議使用雲廠商的SaaS服務,都比較成熟了。而且不用招DBA了,現在好的DBA都在雲廠商那裡。

雲廠商一般都會提供各種監控工具,可以找到資料庫的效能問題。壓測時要重點關注一下資料庫的效能問題,根據經驗,很多時候業務的瓶頸都是因為對資料庫的使用不當造成的。

6.2 資料庫的分片和擴容

不要使用單點資料庫,容易成為系統瓶頸切不容易擴充套件。Mongo可以使用Sharding模式,Redis可以使用叢集模式。

有的資料庫擴容比較容易,有的比較麻煩。要評估一下專案使用的資料庫擴容的成本,若遊戲成功,資料肯定越來越多,若擴容成本很高的話就比較麻煩了。

對於大規模叢集,還要注意資料庫連線數的使用情況。

6.3 資料庫備份和恢復

要對線上環境使用的資料庫設定備份策略,以作為最終的託底。常見的資料庫都有對應的備份方案和策略,運維同學去配置一下即可。

建議遊戲上線前,把遊戲資料庫備份和恢復的流程跑一遍,以保證這個流程是沒有問題的。聽說過業內有的遊戲線上出了大問題,因無法回檔遊戲直接關服下架,這就離了大譜。

七、伺服器部署

遊戲上線前,就要把伺服器叢集部署到真實的線上環境上。這時候,就要考慮哪些程式、哪些服務以何種形式分配線上上的機器上。

7.1 業務隔離

一個有遊戲的分散式叢集往往存在多種型別的程式,每種型別的程式又可能有一個或者N個,我們假設每個程式都是多執行緒的,可以跑滿多個CPU核心。

部署時的業務隔離,只要是防止不同業務程式佔用了較多資源,影響了其他程式的資源使用率。如果使用K8S部署,可以比較容易地做業務隔離,每個程式使用一個pod即可,pod的分配交由K8S管理。若使用虛擬機器部署,則需要考慮哪些程式部署到同一臺機器。

若叢集很小,每個遊戲叢集承載的玩家量也不大(這種情況常見於多邏輯服遊戲,每個邏輯服一個伺服器叢集),一個叢集部署到一臺高配機器上即可。這種方案比較簡單。

若叢集很大,建議儘量一臺機器只部署一個程式,這樣儘量的避免程式間的影響。若有些程式資源佔用較少,也可以多個程式放到一臺機器上。但是儘量保證單點程式或核心邏輯程式與其他程式之間具有隔離,不要讓他們被非核心邏輯影響到。

7.2 上線前的雲資源準備

遊戲上線前,團隊會對玩家量有一個大概的預估。基於玩家量預估以及壓測時對遊戲伺服器的效能評估,我們大概能估計出我們需要多少物理資源。

在遊戲上線前,一定要按照預估玩家量2——3倍的情況去多申請/購買資源,遊戲玩家數量基本穩定後,再將冗餘的機器資源下線。

7.3 環境和配置檢查

上線前一週,要做一次線上環境部署和配置相關的檢查,這種一定要做好double check。

重點關注網路拓撲、資料庫索引、配置資訊、安全等。

八、客戶端相關

不要只關注服務端,一定要知道客戶端是以什麼樣的方式和頻率呼叫服務端介面的,即客戶端呼叫服務端介面的必要性、頻率和流量。

這個在平時開發模組的時候,就應該去透過協作機制或文件保證客戶端呼叫服務端的介面的合理性。

上線之前,建議測試和統計主要遊戲主流程期間(尤其是登入)客戶端對服務端介面的訪問,並且針對訪問的統計結果,進行分析。

對於沒有必要的介面呼叫,可以取消。比如,我們在登陸時,儘量保證玩家不會訪問單點服務,以避免單點服務出現異常時對遊戲登入的影響。

此外,對於介面的訪問頻率和網路流量,也從服務端的角度去評估是否有最佳化的必要。

九、運維工具和平臺

遊戲上線前,要把運維操作基於相關工具和平臺跑通,常見的運維操作包括:

  • 熱更/Hotfix
  • 停服或者不停服維護
  • 修改資料庫或者配置資訊等

對於較小的團隊,建議由公司的服務端開發工程師負責線上的運維工作,不太需要專職運維人員。這樣,可以減少溝通成本,降低事故率。但是,也要把運維工具和線上環境管理好,不要弄混了開發環境和線上環境。

當遊戲伺服器越來越龐大,線上環境越來越複雜,業務場景越來越多,就需要組建專職運維團隊了。

我們使用的是Ansible管理的遊戲伺服器叢集,使用K8S管理平臺(賬號、支付等)伺服器叢集。

小團隊沒必要搭建運維平臺,把運維工具和指令碼做好即可,寫好執行運維操作的CheckList,執行操作時按照List執行。

十、監控和報警

部署遊戲伺服器叢集后,要對機器和業務增加對應的監控和報警。

透過監控,我們要對線上伺服器的情況儘量的瞭解,並且能提前發現問題,防止問題擴大化後才知道。報警和監控相輔相成,監控到異常後,馬上報警,我們就能立刻對線上問題進行處理。

無論是機器的監控還是業務的監控,監控項往往有很多,一定要關注必要的、有價值的監控,防止無效資訊和無效報警淹沒了有效資訊。

十一、安全

網路安全是隨時都需要關注的點,建議遊戲上線前關注以下幾個點:

  • 網路通訊的加密:對網路通訊協議尤其是登陸流程期間,一定要做好網路通訊的加密。
  • 網路訪問控制:確保自己的線上機器是外網不能訪問的,給客戶端只暴露需要的IP和埠。運維同學建議透過跳板機/堡壘機/jumpserver訪問線上機器。
  • DDos:國外的DDos攻擊比要嚴重,提前做好預案和準備。國內的DDos不太嚴重,只有某些特殊型別的遊戲需要重點關注。
  • 許可權控制:做好基本的許可權控制,比如開發環境/線上環境,遊戲資料庫的讀寫許可權等。

客戶端安全(防外掛)是另一個事情了,參考我的另一篇文章:預防為先!遊戲開發中防外掛的那些事兒

對於大部分遊戲型別,不建議中小型團隊過早過多考慮防外掛,做一些記憶體和資源混淆差不多就夠了,建議接入網易易盾或者騰訊ACE。其他價效比太低,而且若遊戲火了再去關注也來得及(遊戲不火也就不用關注了)。

十二、線上事故的預案和演練

線上遊戲出問題甚至事故是個很正常的事情,越火的遊戲越容易出問題。線上出了問題以後,我們能越快的把問題處理好,對玩家的影響就越小。

預案和演練的目的是,讓我們對線上的每個操作,都是可預期的。我們需要知道遇到了各種情況需要使用什麼操作,以及這個操作對應的後果都是明確的。

常見的預案和演練包括:

  • 回檔:無論事故多大,最差能透過回檔解決問題。這個保底,最重要的是兩點:


  • 資料庫有定時備份,比如Mysql和Mongo是能支援按時間點回檔的,Redis也支援針對某個時間點定時備份。
  • 因為即使基於一個時間點,也可能會有資料不一致的問題。所以不同的資料庫之間要想辦法確保一致性,或者互相之間沒有強耦合。


  • 基於日誌或者行為資料根據玩家某些行為進行掃檔,按需獲取玩家列表。


  • 日誌要全。
  • 把日誌系統(比如OpenSearch)用明白。


  • 機器、程式異常演練,明確每臺機器或者每個程式出問題時,使用什麼方案處理。
  • 業務異常:比如可以快速關閉某些系統。


十三、動態擴(縮)容

若我們的遊戲伺服器架構是能支援水平擴充套件的,那麼做動態擴容就不會太複雜。

可以支援以下幾種情況的動態擴容:

  • 手動:當我們發現機器不夠了,可以手動的增加一些機器。
  • 定時:在遊戲活動/遊戲大推期間,或者其他可以預見性的遊戲玩家量較大的時間,可以自動的增加一些機器。(對於大部分遊戲做到這一步就夠了)
  • 自適應:根據玩家的線上量或者機器負載,動態的增加或者減少機器。

對於準備上線的遊戲,動態擴容的遊戲機較高,縮容優先順序低。縮容要考慮優雅退出的機制,所以開發量一般比擴容更大一些。

十四、做好運營工具和平臺

業內遊戲上線後,運營同學發錯獎勵的的例子有很多,大家要關注一下。比如:把人民幣貨幣當成遊戲貨幣發了幾萬個;把發給某些玩家的禮包發給了所有玩家。(這些案例在行業內都出現過)

這種情況不能只怪運營同學,因為人都可能犯錯。我們要把工具、平臺以及工作流做的更加好用一些,減少犯錯的機率和影響範圍,常見的手段比如:

  • 在運營工具和平臺中增加二次確認框,並且提示更加可讀和友好。
  • 增加審批流,每次發放禮包或者重要操作時,需要兩個人check。
  • 增加一些保底機制,比如,不允許發1000以上的人民幣貨幣。

千萬不要讓運營同學有能力直接操作線上,比如執行後臺命令,建議至少做一個簡單的運營工具或者平臺,並且透過工作流程來控制好。

這些工作其實不是技術問題,但是建議在遊戲上線前,和各團隊一起把這些策略定好,防止出現運營事故。

每個遊戲、團隊的情況都不一樣,關注點也有一些區別。若有什麼具體的問題,歡迎友善交流。


原文:https://zhuanlan.zhihu.com/p/611317383

相關文章