pomelo是由網易使在node.js基礎上編寫的服務器框架,其特色爲簡單易用、功能全面,而且具備高可擴展性、可伸縮性等。javascript
具體介紹可參考官方文檔:https://github.com/NetEase/pomelo/wiki/html
如下是摘錄自文檔的框架的簡單優點介紹:前端
使用node.js開發遊戲服務器的優點總結:
1. io與可伸縮性的優點。io密集型的應用採用node.js是最合適的, 可達到最好的可伸縮性。
2. 多進程單線程的應用架構。node.js天生採用單線程, 使它在處理複雜邏輯的時候無需考慮線程同步、鎖、死鎖等一系列問題,
減小了不少邏輯錯誤。由多進程node.js組成的服務器羣是最理想的應用架構。
3. 語言優點。使用javascript開發能夠實現快速迭代,若是客戶端使用html 5,更可實現代碼共用。java
遊戲服務器通常架構:node
運行架構說明:
- 客戶端經過websocket長鏈接連到connector服務器羣。
- connector負責承載鏈接,並把請求轉發到後端的服務器羣。
- 後端的服務器羣主要包括按場景分區的場景服務器(area)、聊天服務器(chat)和狀態服務器等(status), 這些服務器負責各自的業務邏輯。真實的案例中還會有各類其它類型的服務器。
- 後端服務器處理完邏輯後把結果返回給connector, 再由connector廣播回給客戶端。
- master負責統一管理這些服務器,包括各服務器的啓動、監控和關閉等功能。
pomelo的框架介紹
pomelo framework的組成架構如圖所示:git
- server management, pomelo是個真正多進程、分佈式的遊戲服務器。所以各遊戲server(進程)的管理是pomelo很重要的部分,框架經過抽象使服務器的管理很是容易。
- network, 請求、響應、廣播、RPC、session管理等構成了整個遊戲框架的脈絡,全部遊戲流程都構建在這個脈絡上。
- application, 應用的定義、component管理,上下文配置, 這些使pomelo framework的對外接口很簡單, 而且具備鬆耦合、可插拔架構。
-
pomelo的架構設計目標
- 服務器(進程)的抽象與擴展
-
在web應用中, 每一個服務器是無狀態、對等的, 開發者無需經過框架或容器來管理服務器。 但遊戲應用不一樣, 遊戲可能須要包含多種不一樣類型的服務器,每類服務器在數量上也可能有不一樣的需求。這就須要框架對服務器進行抽象和解耦,支持服務器類型和數量上的擴展。github
- 客戶端的請求、響應、廣播
-
客戶端的請求、響應與web應用是相似的, 但框架是基於長鏈接的, 實現模式與http請求有必定差異。 廣播是遊戲服務器最頻繁的操做, 須要方便的API, 而且在性能上達到極致。web
- 服務器間的通信、調用
-
儘管框架儘可能避免跨進程調用,但進程間的通信是不可避免的, 所以須要一個方便好用的RPC框架來支撐。ajax
* 鬆耦合、可插拔的應用架構。json
應用的擴展性很重要, pomelo framework支持以component的形式插入任何第三方組件, 也支持加入自定義的路由規則, 自定義的filter等。
下面分別對這三個目標進行詳細的分析:
服務器(進程)的抽象與擴展介紹
服務器的抽象與分類
該架構把遊戲服務器作了抽象, 抽象成爲兩類:前端服務器和後端服務器
前端:gate,connector 後端:各個邏輯服務器
前端服務器(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
-
Pomelo的框架裏還實現了request的filter機制,廣播/組播機制,詳細介紹見pomelo框架參考。
服務器間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的生命週期圖:
用戶只要實現component相關的接口: start, afterStart, stop, 就能夠加載自定義的組件:
app.load([name], comp, [opts])