版權聲明:本文由韓偉原創文章,轉載請註明出處:
文章原文連接:https://www.qcloud.com/community/article/243程序員
來源:騰雲閣 https://www.qcloud.com/community數據庫
做者介紹:韓偉,1999年大學實習期加入初創期的網易,成爲第30號員工,8年間從程序員開始,歷任項目經理、產品總監。2007年後創業4年,開發過視頻直播社區,及多款頁遊產品。2011年後就任於騰訊遊戲研發部公共技術中心架構規劃組,專一於通用遊戲技術底層的研發。編程
在中國的互聯網諸多業務領域中,遊戲一直是充當「現金牛」而存在的。可是,在遊戲服務器端開發領域中的不少重要問題,並無被明確的分辨出其特異性,從而獲得專門的對待。咱們無論是在業界開源領域,仍是內部分享中,不多會有專門針對遊戲業務特徵進行專門設計的組件、類庫或者框架。咱們從遊戲的客戶端方面來看,一款專業的遊戲客戶端引擎,已是遊戲開發的標配,好比最先的Flash Builder,到後期的Cocos2d-X,Unity,Unreal;可是服務器端,咱們幾乎找不到一樣重量級的產品。瀏覽器
在遊戲服務器端開發全部要面對的問題中,有兩個是最核心和最廣泛的:一是和客戶端的通信;二是遊戲登陸用戶的數據處理。對於和客戶端通信的這個問題,大量的遊戲開發者會使用「通用」的開源組件,好比Protocol Buffer,Thrift,Jetty,Node.js等等通訊或RPC框架。雖然針對遊戲,仍是要作大量的改造,但通常都有不少現成的代碼可供修改。可是對於第二個問題,無論是memcache仍是MySQL,或者是Redis,都不能徹底知足遊戲開發者的需求。不少團隊嘗試過各類組合和修改,試圖創造出利用現有開源軟件,建設既能迎合靈活的需求變化,又具有高延遲和高可用的數據處理系統,但最後這些努力基本上都很難圓滿成功。所以咱們在遊戲服務器端代碼中,仍是充斥着大量的內存、緩存管理,數據同步、落地等等代碼。並且每一個遊戲都要從新去寫一遍這些相似的功能,不能不說一種浪費。緩存
若是咱們要想出一種能知足「遊戲」這個業務領域的數據系統設計,那麼就必定要搞清楚爲何在如此之多的開源項目和遊戲團隊中,沒能實現完美契合的緣由。服務器
電子商務/通常互聯網類業務的數據處理流程
Memcache、Redis、MySQL在通常互聯網業務中的應用很是普遍。並且基本上能很好的應對各類常見的應用場景,包括相似BBS的社區、新聞門戶、電子商務類系統。在企業內部信息系統中(Intranet),這一類數據軟件也能發揮很是好的功效。因爲電子商務類是其中最複雜的系統,因此我在這裏以此爲例說明,通常數據處理的流程是如何的。
網絡
假設咱們瀏覽了一個網店,選中了一個商品,點擊了下單這個流程,實際上須要的後臺流程多是下圖所示:
數據結構
從上面的分析大概能夠總結出幾個特色:架構
- 忍受延遲:每一個操做的延遲要求較低,操做頻率不會過高。通常咱們頁面在5秒內打開,都不會引發太多客戶的抗議。因此,就算咱們處理一個請求的時候,後臺進行屢次的進程間調用,產生的延遲和帶寬消耗也是能夠忍受的。
- 在線交互少:互聯網業務大多數是基於瀏覽器的,因此在線用戶之間不多實時交互。
- 數據分散:通常來講,互聯網應用的數據能夠在多個不一樣的業務系統中共用,可是須要專門的業務模塊來作管理,以維持數據的一致性。
- 數據變動面廣:系統須要持續處理不少數據變動,互聯網業務有很大一部分數據是來源於普通用戶、網絡編輯、店主等等使用者,在使用的過程當中,他們會大量的修改系統所存儲的數據。
以上四個特色,致使了咱們通常會把後臺要處理的數據,分別用Cache系統和DB系統來處理。而且,咱們通常會按業務功能劃分模塊,同時也劃分業務系統。因爲延遲和在線交互的需求較弱,因此使用大量進程來作模塊隔離,依然是很是可行的,整體來講,就是一種比較「分散」的數據使用方式。框架
遊戲類業務的數據處理流程
在各類遊戲中,MMORPG是數據處理最爲複雜的一類,也是最典型的一種「重服務器端」的遊戲類型,所以能夠做爲遊戲業務中通用性的參考標準。在MMORPG中,咱們能夠發現,數據的處理需求,和通常互聯網業務截然不同,它體現出的是一種明顯的「集中」式的數據處理需求。咱們能夠從通常MMORPG的服務器架構中體現出來:

在遊戲業務中,通常咱們都會發現如下的特色:
- 延遲敏感:遊戲中用戶會產生大量操做,都要求「實時」進行反饋,因此通常都不能忍受1秒以上的延遲,在大量動做類型的遊戲中,通常都會要求服務器的反饋時延在50ms左右。所以遊戲開發者都習慣於儘可能減小後臺進程間的交互,儘管這對提升系統吞吐量很不利。因此大部分遊戲服務器端都有一個所謂「GameServer」,裏面運行了遊戲70%以上的功能。
- 大量實時交互:在線遊戲的特色,就是不少玩家能夠經過服務器「看見」彼此,能實時的互動。所以咱們必需要把用戶的在線數據,集中到一塊兒,才能提供互相操做的可能;並且A用戶操做B用戶的數據,是最多見的數據操做,所謂戰鬥玩法,就是互相修改對方的數據的過程。
- 數據集中:遊戲是一個幾乎徹底虛擬的世界,在遊戲中的數據,實際上不多能在其餘系統中產生價值。而遊戲邏輯也禁止經過遊戲之外的方式,修改遊戲的數據。因此遊戲中的數據,通常都會集中存放在單獨的數據庫中。因爲沒有數據共用的需求,因此也不須要把GameServer裏面集中的邏輯劃分出不少單獨的進程模塊來。
- 數據變動少:實際上游戲的數據變動仍是很快的,好比遊戲中的每次中彈,都要減小HP的數值。可是遊戲裏的數據,通常都遵照這樣一個規則:「變化越快的數據,重要性越低」。也就是說,遊戲中是能夠容忍必定程度的數據不一致和不完整的。而遊戲中的數據,通常會分紅兩類:玩家存檔和遊戲設置。對於玩家存檔來講,其單條數據量通常不大,但會有大量的記錄數,由於每一個玩家都會有一個存檔。可是其讀取、修改,通常很典型的和玩家的登陸、登出、升級等業務邏輯密切關聯,因此其緩存時機是比較容易根據業務邏輯來把握的。而對於遊戲設置數據來講,幾乎只有升級遊戲版本的時候纔會修改,大部分運行時是隻讀的,其緩存簡單的讀入內存就解決問題了。
通常的緩存系統的特色在遊戲中的問題
根據以上的分析,咱們能夠看到,普通的緩存系統,如memcache和Redis,實際上其特色是不太適合遊戲業務的:
- 通常跨進程的緩存系統,沒法解決遊戲要求的低延遲問題。級別是同機房,每次數據存取都須要10-20ms的時間,對於遊戲戰鬥中大量的數據讀、寫來講,是很難接受的。(可是一些回合制戰鬥、低頻操做仍是有用的)
- 通用型的緩存系統或者數據庫,通常都比較難集結多個進程,造成一個完整的數據存儲網格。這讓玩家間的互相交互產生了額外的難度,開發者必須先想辦法肯定玩家的數據在哪一個後臺進程上,而後才能去讀寫。通常的數據庫或緩存系統,爲了保證數據的一致性或者完整性,每每會須要犧牲一些分佈式的能力。而這種犧牲在遊戲業務中,實際上是一種浪費,由於遊戲的不少數據都無需這種能力。
- 通用性數據系統通常不依賴於特定的語言,因此不多能直接把某種「對象」存入到數據系統中。在遊戲開發中,須要存儲的數據結構數量每每是很是大量的:一個普通的遊戲,基本上都會超過100種數據結構。對於每一個數據結構,都去建表或者編寫序列化/反序列化配置,是一種很是累人的工做。——明明在代碼中,已經用編程語言定義了他們的結構,還要重複的搞一次。
根據上面說的這些問題,咱們其實是須要另一種徹底不一樣設計思想的數據系統。
本地分佈式緩存服務的特色和優點
對於遊戲業務來講,一個好用的數據系統,應該包括這樣一些特色:
- 能夠利用GameServer進程內的內存進行自動化的緩存管理。因爲GameServer進程每每集中了大部分的邏輯運算,因此大部分的數據緩存也應該在這個進程中,這樣才能符合遊戲所需的延遲要求。
- 自動進行數據落地和容災管理。因爲遊戲數據中有大量的「過程數據」,因此其一致性和完整性要求會稍微低於其餘業務,因此應該利用這一點,讓GameServer自己也能夠是分佈式的程序,從而提升系統總體的吞吐量。
- 具有良好的編程易用性。最好是能直接存取編程中的對象,避免反覆對數據結構的描述,節省大量的開發時間。