pomelo架構概覽

pomelo之因此簡單易用、功能全面,而且具備高可擴展性、可伸縮性等特色,這與它的技術選型和方案設計是密不可分的。在研究大量遊戲引擎設計思路基礎上,結合以往遊戲開發的經驗,肯定了pomelo框架的設計方案。javascript

pomelo爲何採用node.js開發?

node.js自身特色與遊戲服務器的特性驚人的吻合。 在node.js的官方定義中, fast、scalable、realtime、network這幾個特性都很是符合遊戲服務器的要求。遊戲服務器是個網絡密集型的應用,對實時性要求極高,而node.js在網絡io上的優點也徹底能夠知足這點。使用node.js開發遊戲服務器的優點總結:html

  • io與可伸縮性的優點。io密集型的應用採用node.js是最合適的, 可達到最好的可伸縮性。
  • 多進程單線程的應用架構。node.js天生採用單線程, 使它在處理複雜邏輯的時候無需考慮線程同步、鎖、死鎖等一系列問題, 減小了不少邏輯錯誤。 由多進程node.js組成的服務器羣是最理想的應用架構。
  • 語言優點。使用javascript開發能夠實現快速迭代,若是客戶端使用html 5,更可實現代碼共用。

遊戲服務器的運行架構

一個真正高可擴展的遊戲運行架構必須是多進程的。google的gritsgame, mozilla的browserquest 都採用了node.js做爲遊戲服務器開發語言, 但它們都採用了單進程的node.js服務器,缺少擴展性,這使它們能夠支撐的在線用戶數量是頗有限的(這兩個遊戲主要是做爲HTML5遊戲的demo)。而多進程的架構能夠很好的實現遊戲服務器的的擴展性,達到支撐較多在線用戶、下降服務器壓力等要求。前端

一個典型的多進程MMO運行架構, 以下圖所示:

MMO運行架構

說明: 上圖中的方塊表示進程, 定義上等同於「服務器「java

運行架構說明:

  • 客戶端經過websocket長鏈接連到connector服務器羣。
  • connector負責承載鏈接,並把請求轉發到後端的服務器羣。
  • 後端的服務器羣主要包括按場景分區的場景服務器(area)、聊天服務器(chat)和狀態服務器等(status), 這些服務器負責各自的業務邏輯。真實的案例中還會有各類其它類型的服務器。
  • 後端服務器處理完邏輯後把結果返回給connector, 再由connector廣播回給客戶端。
  • master負責統一管理這些服務器,包括各服務器的啓動、監控和關閉等功能。

遊戲運行架構與web應用運行架構的區別

該遊戲運行架構表面上看與web應用運行架構很相似,connector相似於web應用的apache/nginx等web服務器,後端的服務器羣相似於web應用中的應用服務器(如tomcat),但實際上存在着很大的差異:node

  • 長鏈接與短鏈接。web應用使用基於http的短鏈接以達到最大的可擴展性,遊戲應用採用基於socket(websocket)的長鏈接,以達到最大的實時性。
  • 分區策略不一樣。web應用的分區能夠根據負載均衡自由決定, 而遊戲則是基於場景(area)的分區模式, 這使同場景的玩家跑在一個進程內, 以達到最少的跨進程調用。
  • 有狀態和無狀態。web應用是無狀態的, 能夠達到無限的擴展。 而遊戲應用則是有狀態的, 因爲基於場景的分區策略,它的請求必須路由到指定的服務器, 這也使遊戲達不到web應用一樣的可擴展性。
  • 廣播模式和request/response模式。web應用採用了基於request/response的請求響應模式。而遊戲應用則更頻繁地使用廣播, 因爲玩家在遊戲裏的行動要實時地通知場景中的其它玩家, 必須經過廣播的模式實時發送。這也使遊戲在網絡通訊上的要求高於web應用。

如此複雜的運行架構, 咱們須要一個框架來簡化開發

遊戲的運行架構很複雜,要想支撐起如此複雜的運行架構,必需要有一個框架來簡化開發。 pomelo正是這樣一個框架,它使咱們用最少的代碼, 最清晰的結構來實現複雜的運行架構。nginx

pomelo的框架介紹

pomelo framework的組成架構如圖所示:git

pomelo框架

  • server management, pomelo是個真正多進程、分佈式的遊戲服務器。所以各遊戲server(進程)的管理是pomelo很重要的部分,框架經過抽象使服務器的管理很是容易。
  • network, 請求、響應、廣播、RPC、session管理等構成了整個遊戲框架的脈絡,全部遊戲流程都構建在這個脈絡上。
  • application, 應用的定義、component管理,上下文配置, 這些使pomelo framework的對外接口很簡單, 而且具備鬆耦合、可插拔架構。

pomelo的架構設計目標

  • 服務器(進程)的抽象與擴展

在web應用中, 每一個服務器是無狀態、對等的, 開發者無需經過框架或容器來管理服務器。 但遊戲應用不一樣, 遊戲可能須要包含多種不一樣類型的服務器,每類服務器在數量上也可能有不一樣的需求。這就須要框架對服務器進行抽象和解耦,支持服務器類型和數量上的擴展。github

  • 客戶端的請求、響應、廣播

客戶端的請求、響應與web應用是相似的, 但框架是基於長鏈接的, 實現模式與http請求有必定差異。 廣播是遊戲服務器最頻繁的操做, 須要方便的API, 而且在性能上達到極致。web

  • 服務器間的通信、調用

儘管框架儘可能避免跨進程調用,但進程間的通信是不可避免的, 所以須要一個方便好用的RPC框架來支撐。ajax

* 鬆耦合、可插拔的應用架構。

應用的擴展性很重要, pomelo framework支持以component的形式插入任何第三方組件, 也支持加入自定義的路由規則, 自定義的filter等。

下面分別對這三個目標進行詳細的分析:

服務器(進程)的抽象與擴展介紹

服務器的抽象與分類

該架構把遊戲服務器作了抽象, 抽象成爲兩類:前端服務器和後端服務器, 如圖:

服務器抽象

前端服務器(frontend)的職責:

  • 負責承載客戶端請求的鏈接
  • 維護session信息
  • 把請求轉發到後端
  • 把後端須要廣播的消息發到前端

後端服務器(backend)的職責:

  • 處理業務邏輯, 包括RPC和前端請求的邏輯
  • 把消息推送回前端

服務器的鴨子類型

動態語言的面向對象有個基本概念叫鴨子類型。 服務器的抽象也一樣能夠比喻爲鴨子, 服務器的對外接口只有兩類, 一類是接收客戶端的請求, 叫作handler, 一類是接收RPC請求, 叫作remote, handler和remote的行爲決定了服務器長什麼樣子。 所以咱們只要定義好handler和remote兩類的行爲, 就能夠肯定這個服務器的類型。

服務器抽象的實現

利用目錄結構與服務器對應的形式, 能夠快速實現服務器的抽象。

如下是示例圖: 目錄結構

圖中的connector, area, chat三個目錄表明三類服務器類型, 每一個目錄下的handler與remote決定了這個服務器的行爲(對外接口)。 開發者只要往handler與remote目錄填代碼, 就能夠實現某一類的服務器。這讓服務器實現起來很是方便。 讓服務器動起來, 只要填一份配置文件servers.json就可讓服務器快速動起來。 配置文件內容以下所示:

{
  "development":{ "connector": [ {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientPort":3010, "frontend":true}, {"id": "connector-server-2", "host": "127.0.0.1", "port": 3151, "clientPort":3011, "frontend":true} ], "area": [ {"id": "area-server-1", "host": "127.0.0.1", "port": 3250, "area": 1}, {"id": "area-server-2", "host": "127.0.0.1", "port": 3251, "area": 2}, {"id": "area-server-3", "host": "127.0.0.1", "port": 3252, "area": 3} ], "chat":[ {"id":"chat-server-1","host":"127.0.0.1","port":3450} ] } }

客戶端請求與響應、廣播的抽象介紹

全部的web應用框架都實現了請求與響應的抽象。儘管遊戲應用是基於長鏈接的, 但請求與響應的抽象跟web應用很相似。 下圖的代碼是一個request請求示例:

請求示例

請求的api與web應用的ajax請求很象,基於Convention over configuration的原則, 請求不須要任何配置。 以下圖所示,請求的route字符串:chat.chatHandler.send, 它能夠將請求分發到chat服務器上chatHandler文件定義的send方法。

Pomelo的框架裏還實現了request的filter機制,廣播/組播機制,詳細介紹見pomelo框架參考

服務器間RPC調用的抽象介紹

架構中各服務器之間的通信主要是經過底層RPC框架來完成的,該RPC框架主要解決了進程間消息的路由和RPC底層通信協議的選擇兩個問題。 服務器間的RPC調用也實現了零配置。實例以下圖所示:

rpc調用

上圖的remote目錄裏定義了一個RPC接口: chatRemote.js,它的接口定義以下:

chatRemote.kick = function(uid, player, cb) {
}

其它服務器(RPC客戶端)只要經過如下接口就能夠實現RPC調用:

app.rpc.chat.chatRemote.kick(session, uid, player, function(data){
});

這個調用會根據特定的路由規則轉發到特定的服務器。(如場景服務的請求會根據玩家在哪一個場景直接轉發到對應的server)。 RPC框架目前在底層採用socket.io做爲通信協議,但協議對上層是透明的,之後能夠替換成任意的協議。

pomelo支持可插拔的component擴展架構

component是pomelo自定義組件,開發者可自加載自定義的component。 component在pomelo框架參考將有更深刻的討論。 如下是component的生命週期圖:

components

用戶只要實現component相關的接口: start, afterStart, stop, 就能夠加載自定義的組件:

app.load([name], comp, [opts])

總結

上面的應用框架構成了pomelo framework的基礎。在此基礎上,配合pomelo提供的遊戲開發庫和相關工具集,開發遊戲服務器將變得很是方便。 後面的tutorial將帶咱們進入開發遊戲應用的實際案例。轉子

轉自:https://github.com/NetEase/pomelo/wiki/pomelo%E6%9E%B6%E6%9E%84%E6%A6%82%E8%A7%88#%E4%B8%80%E4%B8%AA%E5%85%B8%E5%9E%8B%E7%9A%84%E5%A4%9A%E8%BF%9B%E7%A8%8Bmmo%E8%BF%90%E8%A1%8C%E6%9E%B6%E6%9E%84-%E5%A6%82%E4%B8%8B%E5%9B%BE%E6%89%80%E7%A4%BA

相關文章
相關標籤/搜索