天天看點

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 。