pomelo


pomelo架構概覽

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

pomelo為什么采用node.js開發?

node.js自身特點與游戲服務器的特性驚人的吻合。 在node.js的官方定義中, fast、scalable、realtime、network這幾個特性都非常符合游戲服務器的要求。游戲服務器是個網絡密集型的應用,對實時性要求極高,而node.js在網絡io上的優勢也完全可以滿足這點。使用node.js開發游戲服務器的優勢總結:

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

游戲服務器的運行架構

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

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

MMO運行架構

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

運行架構說明:

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

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

該游戲運行架構表面上看與web應用運行架構很類似,connector類似於web應用的apache/nginx等web服務器,后端的服務器群類似於web應用中的應用服務器(如tomcat),但實際上存在着很大的差別:

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

如此復雜的運行架構, 我們需要一個框架來簡化開發

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

pomelo的框架介紹

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

pomelo框架

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

pomelo的架構設計目標

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

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

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

客戶端的請求、響應與web應用是類似的, 但框架是基於長連接的, 實現模式與http請求有一定差別。 廣播是游戲服務器最頻繁的操作, 需要方便的API, 並且在性能上達到極致。

  • 服務器間的通訊、調用

盡管框架盡量避免跨進程調用,但進程間的通訊是不可避免的, 因此需要一個方便好用的RPC框架來支撐。

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

應用的擴展性很重要, 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM