天美J3工作室服務器主程:我們怎麼避免上線即炸服?
編者按在8月29日的GWB遊戲品鑑會上,騰訊天美工作室《使命召喚手遊》服務器主程Jerry,分享了服務器架構如何優化以及常見的服務器問題解決方案,以下為文字版本。
分享/Jerry 整理/迪亞菠蘿包
炸服,是近兩年頻繁發生、遊戲廠商聞之色變的運營事故。
雖然從某種意義上來説,炸服意味着遊戲很受歡迎,但由於炸服會致使玩家無法登錄、頻繁卡頓、反覆重連,甚至出現數據丟失和回檔,導致遊戲口碑暴跌。一旦處理不好,可能會使一個原本的爆款喪失第一波爆發的機會。
從服務器架構設計的角度,如何避免上線即「炸服」的事故發生?
上週六,在騰訊遊戲學院主辦的GWB騰訊遊戲品鑑會上,天美J3工作室《使命召喚手遊》服務器主程Jerry分享了他對於服務器架構設計的心得。
其分享的要點如下:
看完這篇技術乾貨,説不定能幫助你的產品避開炸服雷區。
《使命召喚手遊》服務器主程序Jerry
以下為分享內容,有調整和刪節。
大家好,我是Jerry,來自天美J3工作室,現在擔任《使命召喚手遊》服務器主程。很高興有機會和大家聊一聊有關服務器架構設計的話題。
今天這個話題,想必大家都會有所關注:遊戲上線後出現炸服,可能是因為哪些原因?在遊戲設計之初,我們需要注意哪些問題,才能避免或減少炸服發生?
那什麼是炸服?我相信大家都聽説或經歷過這樣的情況,遊戲剛開服的時候,由於玩家特別熱情,可能出現登錄不上、頻繁卡頓,甚至反覆重連的情況,嚴重時可能會出現數據丟失、回檔,而且這些問題往往不能快速得到解決。
從服務器設計的角度看,這些問題一般和下面這些因素有關:服務器架構設計不到位、平行擴容和負載均衡有缺陷、單點容災考慮得不是特別完善。
我們先從一個案例講起。這是某款遊戲的服務器架構圖,我們做了適當的簡化。
這款遊戲採用了分區分服的部署方式,架構圖左邊其實是一個區,主要包含登錄授權服務,以及連接管理和遊戲邏輯。同時,它有一個所有分區公用的對局管理模塊,而它的遊戲邏輯放在了戰鬥邏輯進程中,也是各個分區共同使用。
在功能層面,這款遊戲的連接管理主要負責玩家的連接登錄,遊戲邏輯裏包含了數據管理,角色養成等業務邏輯,而對局管理包含組隊、匹配、開局邏輯等等,戰鬥邏輯主要負責局內戰鬥。
這款遊戲在部署上有一個很有意思的點,開發團隊認為這款遊戲單區承載能力足夠,因此打算一個大區用一台高性能物理機、主遊戲邏輯用一個進程就搞定了。
這樣的架構設計存在什麼問題?首先業務耦合度特別高。他們在架構圖裏雖然把連接管理和遊戲邏輯分開了,但實際上這兩塊在同一個進程中。連接管理和遊戲邏輯放在一起可能會導致什麼問題?
對於這款遊戲來説,遊戲邏輯裏包含了很多遊戲,所以業務邏輯會特別重,出現Bug的概率特別高,如果在線上運營,遊戲邏輯可能需要頻繁更新,如果將其和連接管理放在一起,會導致更新出現各種掣肘,一旦處理不當,就有可能導致玩家掉線。
其次,他們的對局管理模塊包含了很多功能,比如匹配、開局、負載管理等等,由於全局只有一個對局邏輯,所以可能會存在單點容災的問題。而對局管理和遊戲邏輯放在一起,平行擴容方面也會存在問題。同時,由於他們把負載管理和匹配之類的功能放在同一個進程裏面,在負載管理上可能也存在一些缺陷。
拓展一點説,在分區分服部署模式中經常會碰到另外一個問題:由於開發者認為遊戲是分區分服的,每個區的玩家數量相對會比較少,所以他們只部署一個進程來搞定,從單區的角度來看形成了事實上的單點。
而這款遊戲全服共享的「對局管理」只有一個進程,我們認為如果單進程能支撐所有的請求,那麼至少應該設計成主備部署的架構。但在遊戲上線前,你拿不準用户量會達到什麼樣的程度。萬一你的遊戲成了爆款,這種單純的主備方式有可能滿足不了實際的需求。因此,我們推薦將其設計成可以平行擴容的方案。
説到平行擴容,剛才那種事實單點是無法支持平行擴容的。對於這個項目,他們負責服務器設計的同學説,單區承載目標是5K-6K,但隨着開發推進,遊戲業務邏輯越來越複雜,通過壓力測試發現,在這種邏輯架構下,遊戲邏輯進程承載的極限只有3K。由於這種架構不支持平行擴容,遊戲上線時很有可能發生炸服。
這款遊戲的對局管理為什麼不支持平行擴容?因為對局管理進程中包含的功能太多了,這些功能在同樣的業務邏輯下,對性能的要求可能不一樣。如果想要對其中某個功能進行擴容,在這種把所有功能都集成在一起的設計中顯然做不到。
除此之外,這款遊戲還存在負載均衡的問題,這個和架構設計可能沒有太大關係,我們發現,這款遊戲的對局管理存在算法缺陷。因為他們沒有考慮到一台機器的瞬間負載能力,在新加入「戰鬥模塊」機器時,可能發生雪崩。
因此我們設計負載均衡調度算法時,除了定時上報負載外,一定要設計異常上報機制,負載均衡算法必須能及時處理異常情況,並且實例——對於這款遊戲就是戰鬥模塊——必須要有主動熔斷機制,避免出現負載本身已經承受不住時,負載調度模塊還不斷髮送開局請求,當然這需要負載調度模塊和實例之間互相配合。
同時,我們還需要設計提前預判機制。舉個例子,目前我只剩下10%的負載,下一次上報時間可能在3秒以後,如果這3秒內調度模塊發送了過多請求,很有可能會導致雪崩。
總體看下來,如果這款遊戲以這樣的服務器架構上線,萬一玩家特別熱情,剛才提到的任何一個問題爆發,都有可能引發「炸服」。
在這個案例中,我們指出了很多問題,也相應提供瞭解決方案,但項目組反饋説,可能沒有辦法做這樣的修改,因為他們在設計之初就把服務器架構限死了,並且服務器底層架構缺乏相關的支持。
那我們在架構設計之初,能不能做一些預見性的設計,規避這樣的問題?