Node.js 之網遊服務器實踐

隨着 Node.js 的不斷髮展與壯大,應用範圍也越來越廣泛,從傳統的企業應用,到互聯網使用,再到雲計算的發展,它的身影也是隨處可見。當然,它的受歡迎程度能在短時間內得到這麼快的發展,除卻與其本身的事件模型及 V8 的性能優化等一系列特性有關之外,還和國內外很多互聯網公司的攻城師的大量應用和參與到開源項目中有密切關係,如網易的遊戲開發,淘寶的數據之美等等。隨着 HTML5 應用和移動互聯網平臺的指數增長,越來越多的用戶使用了移動平臺的休閒服務,採用 Node.js 實現高性能和可擴展性的遊戲服務將是一件有意義的工作。

在互聯網上,目前有一些採用 Node.js 實現的開源遊戲服務框架,如 Mozilla 的 Browser Quest , Google 的 Grits  Chilly 等。但是無一例外,這些框架不但與遊戲邏輯聯繫緊密,而且幾乎沒有可擴展性和性能數據,同時也不提供任何遊戲開發的管理工具,除了採用 JavaScript 編寫外,很難體現出採用 Node.js 實現遊戲開發的優越性。

概念

通常遊戲分爲角色扮演類和策略類及混合類等幾種遊戲類型。那麼在網頁遊戲類型中,根據遊戲的類型,開發者可能採用不同的架構實現方式,如策略類遊戲可能更偏重於遊戲的策略性和邏輯性,也就是考驗遊戲玩家的各種組合或搭配之類的遊戲,對實時性的要求不會很高,在用戶的可接受範圍之內即可,因此也可以採用常用的 Web 應用開發模式來實現,而客戶端採用輪詢或長連接等方式來實現,這些應用模式也有很多的相關經驗可以參考,因此能做到具有較好的可擴展性及伸縮性;此外,應用服務器和服務框架等也可以採用現存的技術實現,但是這隻能滿足對遊戲實時性要求不高的場景服務,由於此類的應用方案非常成熟,在下文的討論中,將不再詳述。

角色扮演類遊戲根據策劃的要求可以實現各種各樣的功能,如聊天,打鬥,自動刷怪等各種複雜的功能,但是開發者基本可以把這些功能抽象地劃分爲二大類,即服務端的網絡傳輸與邏輯運算能力,這樣遊戲服務的開發和實現會稍微簡單些。現在,網絡的實時傳輸基本上是採用 Socket 服務器來實現的,邏輯運算這個就不需要再述了,因此,遊戲服務器就可以粗略的歸納爲 Socket 的服務器綜合遊戲業務邏輯的實現。

與 Web 應用區別

從上面遊戲服務的概念簡單介紹中可以得知,實時遊戲服務器的開發與傳統的 Web 開發還是具有一些不同點,這些不同點着重體現在以下幾個方面:

  1. 大部分的 Web 應用還是短連接的方式去實現,而遊戲的實時性需要採用長連接的方式進行。
  2. Web 應用的場景一般是讀多寫少的應用,熱點數據基本可以緩存;遊戲服務的數據經常發生變動,如移動中的路徑,打怪掉血等,緩存基本很快就失效,屬於寫多讀少的應用場景。
  3. 廣播特性,即 Web 應用行爲上基本只需要用戶與服務器交互,其他用戶要實現共享他人信息的時候,會採用類似拉的方式如長輪詢來實現數據交互,即使在沒有數據更新的狀態時也需要消耗一定的服務端資源,造成一定的浪費;遊戲裏面的交互方式需要實時進行,對影響三方的數據,必須採用廣播的方法進行消息推送,即推的模式。
  4. 目前的 Web 應用開發一般採用無狀態性的方式來實現,因此可以實現較好的可擴展性,很多 Web 服務會採用綁定會話或集中會話等方式工作,當後面的某臺服務器出現宕機時,服務也可以很快的切換;但是遊戲服務器和用戶之間的連接是有狀態的,在斷開時需要進行相關的通知和數據持久化,在重連時需要進行狀態恢復等手段來維護遊戲世界的運行。

除以上幾點不同之外,還有負載均衡的策略,服務驅動方式,系統判定,系統安全如外掛作弊等相關問題,文章中不再對他們進行對比說明。一般來講,根據遊戲的規模與需求,通常遊戲服務器的實現的模式會使用如下的三種架構方式來實現。

單進程服務架構

圖 1 單進程服務架構

圖 1 是目前互聯網上的很多遊戲服務器使用的架構,比如商用的 SmartFoxServer 遊戲服務器, 開源的有 Google 的 Grits , Mozilla 的 Browser Quest 等框架。所有的程序在同一個進程裏面運行,架構簡單,開發人員上手快,開發和調試非常方便又快速,成本較低,後期的維護成本可能隨着遊戲項目的大小而不同,但是整體應該不會太高。很明顯,遊戲的世界是在同一個進程裏運行,在單個場景都有不少在線用戶的時候,如果採用單進程的 Node.js 實現的話,每個用戶的操作可能會有一定的延遲,特別是在大量用戶同時做大量操作與 AI 運算時,如服務端尋路和自動殺怪,延遲會更加嚴重;同時單進程對計算機資源使用有限。因此只適合遊戲的原型製作或小型的遊戲開發。另外,由於遊戲的狀態與複雜性,也無法較好的實現遊戲的可擴展性,基本只能通過添加遊戲服務器的方式來實現,即所謂的開新服,而這些用戶之間是無法在同一個世界裏通信會話和交互的。儘管 Node.js 支持原生的 TCP 服務,使用簡單;但是目前大部分網絡應用中,尤其是支持 HTML5 的應用, socket.io 由於性能較好並且使用簡單,成爲大部分應用採用的網絡庫來實現高性能 websocket 服務。在移動互聯網應用中,由於協議較複雜與通信數據等問題,需要一定的裁減。下面示例中,就是最簡單的單進程服務的原型:

var socketio = require('socket.io');
var io = socketio.listen(8080);
io.sockets.on('connection',function(socket){
     socket.on('disconnect',function(){
     //user leave
     });
 socket.on('message',function(msg){
     if (getLoginStatus(socket)) {
     game[data.action].apply(null,[socket,msg]); 
     } else {
     game['login'].apply(null,[socket,msg]); 
     }
 });
});

多進程服務架構

圖 2 多進程服務架構

在上圖 2 中,我們可以看出,每個進程負責採用單一職責,各進程間通過一定的規則(如 RPC 遠程過程調用)來進行通信,遊戲中的各場景服務使用一個進程來服務,實現各場景遊戲運行的分離。但是在開發過程中,不需要考慮每個場景具體的信息,全部採用統一的代碼來實現,開發方便,通過添加適當的參數來實現較易的調試,每個進程分別運行在服務器的多核上,即可以充分使用計算機的資源,也由於職責單一,由於每個進程都專職做自己的事,因此,在壓力大的時候,可以很明顯的查出問題所在,並可以較好的實現對相應的服務進行調優,可以達到較好的性能和一定的可伸縮性。但是,在各遊戲的世界裏,無法準確的知道遊戲的狀態如在線人數之類的,會存在熱點數據和服務過載等一些問題,造成部分服務堵死等現象,也無法達到在不停服務的情況下進行服務器擴容與自動切換等問題,同時會給遊戲運營帶來一定的問題,不能充分的對玩家數據進行分析與挖掘,因此,這種實現方式可以滿足中小型的遊戲開發。這種架構目前很多的遊戲服務器中還在使用,技術發展也較成熟,如傳奇服務端架構等。

分佈式服務架構

圖 3 分佈式的服務架構

同樣,分佈式的服務架構與多進程的架構具有很多相同點,如進程服務單一職責,較好的性能調優,同時採用集中式的方式對遊戲服務器進行管理,各遊戲服務器可以通過自定義的方式即 DSL 進行遊戲業務的路由與分發,通過主備服務器的狀態可以很清楚的知道每個服務的狀態及運行情況,這樣可通過動態添加服務來到達負載均衡,具備較好的性能和可擴展性,能滿足大型遊戲的開發。當然,採用這樣方式,會具有一定的複雜性,同時各服務之間可能是不在同一臺服務器上的,因此會帶來一定的網絡開銷,在大量廣播的場景中,網絡 IO 壓力大,需要通過定時批量或 AOI 服務等方式來進行廣播通信,同時,遊戲的通信協議需要經過特別的設計,儘量避免數據序列化上的 CPU 重複開銷,採用胖客戶端的方式去分擔遊戲服務器的序列化與反序列化;另外還有可能引入分佈式事務等相關問題,需要在一個集中點進行處理。當然,在遊戲設計中,策劃開發人員需要儘量避免這種跨場景跨進程的遊戲邏輯需求。

在分佈式架構實現中,目前商業上較成功的案例是 BigWorld 遊戲服務框架,國內外很多大型的遊戲開發商都在使用。而在開源部分,目前還沒有較穩定成熟的方案,我們團隊採用 Node.js 正在開發的 Pomelo 遊戲服務框架正在努力實現這一目標,現已進入最後的文檔整理階段,預計將在十月份進行開源與線上示例演示。

總結

採用 Node.js 來實現網絡遊戲服務器的開發,除了能利用 JavaScript 的動態語言的優勢特性、強大的開源社區和 V8 引擎的優越性能外,在網絡數據傳輸的異步化方面具有快速、實時等事件編程模型;特別在 HTML5 的應用開發中,還具有前後端代碼共享、DSL 靈活定義等特點。但是也由於 JavaScript 的動態腳本語言的性質,同時 V8 在內存使用上的限制等問題。儘管 V8 引擎對腳本語言通過動態編譯進行了靜態化,但如果開發工程師在大規模開發時,沒有注意到一些代碼的細節,比如代碼的額外異常檢查和類屬性的動態變化等方面,導致未經過調優的代碼整體上還是無法和 C、Java 等靜態語言相比的,然而在經過調優過後的代碼是可以達到靜態語言的性能的。在雲計算應用中,也得到很多公司的推廣與使用,如國外的 SmartOS,Vmware 以及國內的阿里雲等,相信其性能與應用層面都會發展的越來越好;

此外,採用 Node.js 來實現遊戲服務框架並開源也是一件非常有價值的事情,在追求高性能與低成本同時,希望能給開發者提供即簡單又快速的開發方式,遊戲開發者通過使用遊戲框架,可以完全把精力放在業務代碼的實現,不需要再把精力放在框架的實現。有機會我們將在後面的一系列討論中介紹採用 Node.js 來開發遊戲服務架構遇到的很多性能問題及優化過程。 最後,本文並不是建議大家一定要採用 Node.js 去開發遊戲服務器,只是給新老遊戲開發者提供一種解決方案,歡迎大家關注和探討我們團隊近期將開源的 Node.js 遊戲服務解決框架。

個人介紹:

堯飄海,網易杭州開發工程師,系統分析員,正致力於 Node.js 的移動遊戲引擎開發和性能優化等方面的工作,同時對 JVM 性能和服務端的應用架構設計也很有興趣,歡迎交流。個人 Github 地址: http://github.com/piaohai 

轉自https://www.infoq.cn/article/nodeJs-online-game/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章