精华内容
下载资源
问答
  • Pomelo

    千次阅读 2019-11-14 20:39:12
    Pomelo(柚子)是基于Node.js的高性能分布式游戏服务框架,它包含基础的开发框架和相关的扩展组件(库和工具包)。Pomelo不但适用于游戏服务器开发也可以用于开发高实时的Web应用,它的分布式架构使Pomelo比普通实时...
        

    Pomelo(柚子)是基于Node.js的高性能分布式游戏服务框架,它包含基础的开发框架和相关的扩展组件(库和工具包)。Pomelo不但适用于游戏服务器开发也可以用于开发高实时的Web应用,它的分布式架构使Pomelo比普通实时Web框架性能更好。

    Pomelo是游戏服务器框架,本质上也是高实时、高扩展、多进程的应用框架,除了在提供的库部分有游戏专用的库,其余部分框架完全可用于开发高实时的应用。而且与现有的Node.js高实时应用框架如Derby、Socketstream、Meteor等相比具有更好的可伸缩性。

    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开发可以实现快速迭代,若客户端使用HTML5,更可实现代码共用。

    游戏服的运行架构

    高可扩展的游戏运行架构必须是多进程的,Google的Gritsgame,Mozilla的Browserquest都采用了Node.js作为游戏服开发语言,它们都采用了单进程的Node.js服务器,由于缺乏扩展性,使它们可以支撑的在线用户数量是有限的。而多进程架构可以很好的实现游戏服的可扩展性,达到支撑较多的在线用户、降低服务器压力等要求。

    典型多进程MMO运行架构

    4933701-e51f123b558e2b46.png
    多进程MMO运行架构
    • 客户端client通过websocket长连接到前端connector服务器群,connector连接器负责承载连接,并将request请求转发到后端服务器群。
    • 后端服务器群包含按场景分区的场景服务器area,聊天服务器chat、状态服务器status,这些服务器负责各自的业务逻辑。
    • 后端服务器负责处理完逻辑后将结果返回给前端连接器,再由连接器广播回给客户端。
    • master负责统一管理这些服务器,包括各服务器的启动、监控、关闭等功能。

    架构将游戏服做了抽象,抽象成两类:前端服务器、后端服务器

    前端服务器(frontend server)

    • 负责承载客户端请求的连接
    • 维护Session会话信息
    • 将请求转发到后端
    • 将后端需广播的消息发送到前端

    后端服务器(backend server)

    • 处理业务逻辑包括RPC和前端请求的逻辑
    • 将消息推送回前端

    游戏运行架构 & Web应用运行架构

    游戏运行架构 Web运行架构
    前端服务器 Web服务器,如Apache/Nginx
    后端服务器 应用服务器,如Tomcat

    游戏运行架构与Web应用运行架构的区别

    • 长连接与短连接
      Web应用使用基于HTTP的短连接以达到最大的可扩展性,游戏应用采用基于Socket(WebSocket)的长连接以达到最大的实时性。

    • 分区策略
      Web应用的分区可根据负载均衡自行决定,游戏则是基于场景的分区模式,这使同场景的玩家跑在一个进程内以达到最少的跨进程调用。

    • 有无状态
      Web应用是无状态的,可以达到无限的扩展。游戏应用是有状态的,由于基于场景的分区策略,游戏的请求必须路由到指定的服务器,这也使游戏达不到Web应用同样的可扩展性。

    • 通讯方式
      Web应用基于请求响应模式,游戏应用则更为频繁的使用广播,由于玩家在游戏里的行动要求实时地通知场景中的其它玩家,必须通过广播的模式实时发送,这也使游戏在网路通信上的要求高于Web应用。

    框架定位

    Pomelo是一个轻量级的服务器框架,最合适的应用领域是网页游戏、社交游戏、移动游戏的服务端。不推荐将Pomelo作为大型MMORPG游戏开发,尤其是大型3D游戏,这需要像BigWorld商用引擎来支撑。

    框架特性

    • 基于Socket.io开发
    • 多进程架构:支持MMO场景分区和其他各类分区策略
    • 服务器扩展:快速扩展服务器类型和数量。
    • 通讯机制:请求、响应、广播
    • 扩展组件

    框架组成

    • Server Management
      多进程分布式游戏服武器,各游戏Server进程的管理是框架很重要的部分,框架公国抽象使服务器的管理非常容易。
    • Network
      请求、响应、广播、RPC、Session管理
    • Application
      应用的定义,组件管理,上下文配置
    4933701-eb979d202c110a6d.png
    柚子框架

    架构目标

    • 服务器进程的抽象与扩展
      Web应用中每个服务器是无状态且对等的,开发者无需通过框架或容器来管理服务器。但游戏不同,游戏可能需要包含多种不同类型的服务器,每种服务器在数量上也可能有不同的需求。这就需要框架对服务器进行抽象和解耦,支持服务器类型和数量上的扩展。
    • 客户端的请求响应、广播
      客户端的请求响应与Web应用类似,但游戏框架是基于长连接的,实现模式与HTTP请求有一定差异。广播是游戏服务器最频繁的操作,需要方便且高性能的API。
    • 服务器间的通讯和调用
      尽管框架尽量避免跨进程调用,但进程间的通讯是不可避免的,因此需要一个方便好用的RPC框架做支撑。
    • 松耦合可插拔
      框架支持以组件的形式插入任何第三方组件,也支持加入自定义的路由规则,自定义的过滤器等。

    框架优势

    • 可伸缩性好
      架构采用多进程单线程的运行架构,扩展服务器方便。
      Node.js的网络IO优势提供了高可伸缩性。
    • 使用方便
      开房模式与Web应用的开发类似,都是基于Convention Over Configuration的理念,零配置。
    • 松耦合可扩展
      遵循Node.js微模块原则,框架所使用的类库组件都是以NPM Module的形式扩展进来。

    安装配置

    环境准备

    • 操作系统 Windows10
    • Python版本:2.5~3.0
    • Visual Studio2010

    全局安装框架

    $ npm i -g pomelo
    

    查看帮助

    $ pomelo -h
      用法: pomelo [选项] [命令]
      命令:
        init [path]            创建一个新的应用
        start [options]        开启应用
        list [options]         列出所有的服务器
        add [options]          添加一个新的服务器
        stop [options]         关闭服务器,多个服务器可使用 `pomelo stop server-id-1 server-id-2`
        kill [options]         杀死应用
        restart [options]      重启服务器,多个服务器可使用`pomelo restart server-id-1 server-id-2`
        masterha [options]     开启主从模式下所有的从服务器
        *
      选项:
        -h, --help     输出用法信息
        -V, --version  输出版本号
    

    创建项目

    $ cd workspace
    
    $ pomelo init ./test
    默认管理员用户:
      账户: admin
      密码: admin
    可编辑adminUser.json文件配置管理员用户
    请选择底层连接器: 1 websocket(原生 socket), 2 socket.io, 3 wss, 4 socket.io(wss), 5 udp, 6 mqtt: [1]
    

    目录结构

    目录文件 描述
    game-server 游戏服务器,以app.js文件为入口。
    shared 前后端、游戏服、Web服共用代码
    web-server Web服务器,Express框架搭建,以app.js为入口。

    游戏服目录

    目录 描述
    game-server/app 游戏服应用开发目录,实现不同类型的服务器,添加对应Handler和Remote等。
    game-server/config/ 游戏服配置文件目录,配置文件以JSON格式定义。
    game-server/logs/ 游戏服日志目录
    game-server/app.js 游戏服入口文件

    Web服目录

    目录文件 描述
    web-server/bin/ Web服应用保存目录
    web-server/public/ Web服静态文件保存路径
    web-server/app.js Web服入口文件

    安装项目

    $ cd test
    $ npm-install.bat
    

    安装脚本执行的步骤

    $ cd ./game-server && npm install -d
    $ cd ./web-server && npm install -d
    

    启动项目

    启动项目必须分别启动游戏服和Web服

    • 启动游戏服命令
    $ cd game-server && pomelo start
    

    启动命令

    $ pomelo start [development|product] [--daemon]
    
    命令参数 描述
    development 默认,开发模式
    product 产品环境
    --deamon 后台运行

    后台运行模式--daemon需forever模块支持

    $ npm i -g forever 
    

    项目应用启动命令

    $ pomelo start -h
      用法: start [选项]
      选项:
        -h, --help                    输出用法信息
        -e, --env <env>               指定环境
        -D, --daemon                  以后台守护进程模式启动
        -d, --directory, <directory>  指定代码目录
        -t, --type <server-type>,     指定服务器类型启动
        -i, --id <server-id>          指定服务器ID启动
    
    • 启动Web服命令
    $ cd web-server && node app
    

    访问Web服:http://127.0.0.1:3001

    查看游戏服务器状态

    $ cd test
    
    $ pomelo list
    try to connect 127.0.0.1:3005
    serverId           serverType pid   rss(M) heapTotal(M) heapUsed(M) uptime(m)
    connector-server-1 connector  8288  37.84  21.83        17.02       5.48
    master-server-1    master     22696 35.04  19.83        14.88       5.48
    

    游戏服务器状态信息

    字段 含义
    serverId 服务器编号,从config配置表中的ID。
    serverType 服务器类型,同config配置表中的type。
    pid 服务器对应的进程PID
    rss -
    heapTotal 服务器使用堆内存总大小,单位MB。
    heapUserd 服务器已使用堆内存大小,单位为兆(MB)。
    uptime 服务器启动时长,单位为分钟。

    关闭项目

    $ cd test
    $ pomelo stop [id]
    

    pomelo stop优雅地关闭各个服务器

    • 前端服务器首先断开连接,阻止新玩家进入游戏,用户体验好。
    • 各个服务器按顺序关闭自身的功能,保证游戏逻辑正常。
    • 玩家状态等信息及时写入数据库,保证数据完整性。

    pomelo stop id会关闭指定ID的服务器,关闭特定服务器会导致服务器状态信息等丢失,建议先做好服务器状态信息的维护和备份。

    杀死进程

    $ cd test
    $ pomelo kill [--force]
    

    pomelo kill会直接杀死项目进程,做法比较粗暴,安全性低,开发环境下可以使用,产品环境慎用。若有残留进程杀不干净,可添加--force参数。

    动态添加服务器

    $ cd test
    $ pomelo add  host=[host] port=[port] id=[id] serverType=[serverType]
    

    目前只支持后端服务器的动态添加

    管理控制器

    $ apt-get install sysstat
    
    $ git clone https://github.com/NetEase/pomelo-admin-web.git
    $ cd pomelo-admin-web
    $ npm i -d
    $ node app
    
    $ vim config/admin.json
    {
        "host": "localhost", 
        "port": 3005,
        "username": "monitor",
        "password": "monitor"
    }
    

    Chrome浏览器访问:http://127.0.0.1:7001

    术语

    鸭子类型

    动态语言面向对象有鸭子类型的概念,服务器的抽象也同样可以比喻为鸭子,服务器的对外接口只有两类:

    • handler:接收客户端的请求
    • remote:接收RPC请求

    handler和remote的行为决定了服务器长什么样子,只要定义好handler和remote两类的行为,就可以确定这个服务器的类型。

    网关服务器 gate

    • 一个应用的gate一般不参与RPC调用,也就是说其配置项里可以没有port字段,仅仅有clientPort字段,它的作用是做前端的负载均衡。
    • 客户端往往首先向gate发出请求,网关会给客户端分配具体的connector。具体的分配策略一般是根据客户端的某个key做hash得到connector的ID,这样就可以实现各个connector的负载均衡。

    连接服务器 connector

    • connector接收客户端的连接请求,创建与客户端的连接,维护客户端的session会话信息。
    • connector接收客户端对后端服务器的请求,按照用户配置的路由策略,将请求路由给具体的后端服务器。当后端服务器处理完请求或需要给客户端推送消息的时候,connector同样会扮演一个中间角色,完成对客户端的消息发送。
    • connector会同时拥有clientPort和port,其中clientPort是用来监听客户端的连接,port端口用来给后端提供服务。

    应用逻辑服务器

    • gate和connector又称为前端服务器,应用逻辑服务器是后端服务器,它完成实际的应用逻辑,并提供服务给客户端,当然客户端的请求是通过前端服务器路由过来的。
    • 后端服务器之间也会通过RPC调用而有相互之间的交互,由于后端服务器不会跟客户端直接有连接,因此后端服务器只需监听它提供服务的端口即可。

    主服务器 master

    master加载配置文件,通过读取配置文件,启动所配置的服务器集群,并对所有服务器进行管理。

    RPC调用 rpc

    Pomelo中使用RPC调用进行进程间通信,在Pomelo中RPC调用分为两类:使用namespace命令空间进行区分,namespacesys的是系统RPC调用,它对用户来说是透明的,目前Pomelo中系统RPC调用有:

    • 后端服务器向前端服务器请求session会话信息
    • 后端服务器通过channel推送消息时对前端服务器的RPC调用
    • 前端服务器将用户请求路由给后端服务器时也是sys rpc调用

    除了系统RPC调用之外,其余的由用户自定义的RPC调用属于user namespace的RPC调用,需要用户自己完成RPC服务端remotehandler代码,并由RPC客户端显式地发起调用。

    路由 router

    route是用来标识一个具体服务或客户端接受服务端推送消息的位置,对服务器来说,其形式一般是:chat.chatHandler.send,其中chat是服务器类型,chatHandler是chat服务器中定义的一个Handler,send则是这个Handler中的一个handler方法。

    对客户端来说,其路由形式一般为onXXX,当服务端请求到达后,前端服务器会将用户客户端请求派发到后端服务器,这种派发需要一个路由函数router,可以粗略地认为router是根据用户的session以及其请求内容做一些运算后,将其映射到一个具体的应用服务器ID。

    可以通过application的route调用给某一类型的服务器配置其router。若不配置的话,Pomelo会使用一个默认的router。

    Pomelo默认的路由函数是使用session里面的uid字段,计算uid字段的crc32校验码,然后用这个校验码作为key,跟同类应用服务器数目取余,得到要路由到的服务器编号。注意这里有一个陷进,如果session没有绑定uid的话,此时uid字段为undefined,可能会造成所有请求都路由到同一台服务器,所以在实际开发中还是需要自己来配置router。

    会话 session

    Session会话是指一个客户端连接的抽象,Pomelo框架中有三个session会话的概念分别是Session、FrontendSession、BackendSession。

    session会话字段结构

    {
      id:<session id>//readonly
      frontendId: <frontend server id> //readonly
      uid: <bound uid> // readonly
      settings: <key-value map> //read and write
      __socket__: <raw_socket>
      __state__: <session state>
      //...
    }
    
    字段 权限 描述
    id 只读 当前session会话的ID,全局唯一,自增方式来生成。
    frontendId 只读 维护当前session会话的前端服务器的ID
    uid 只读 当前session会话所绑定的用户ID
    settings 读写 维护key-value map用来描述session会话的自定义属性
    __socket__ 只读 底层原生socket的引用
    __state__ 只读 用来指明当前session会话的生命周期状态

    一个session会话一旦建立,那么idfrontendIduid__socket____state__都是确定的,都应该是只读不可写的。而settings也不应该被随意修改。因此在前端服务器中引入了FrontendSession可将其看作是一个内部session会话在前端服务器中的傀儡。

    FrontendSession的字段结构

    {
      id: <session id> // readonly
      frontendId: <frontend server id> // readonly
      uid: <bound uid> // readonly
      settings: <key-value map> // read and write
    }
    

    FrontendSession的作用

    • 通过FrontendSession可以对settings字段进行设置值,然后通过调用FrontendSession的push()方法,将设置的settings的值同步到原始的session会话中。
    • 通过FrontendSession的bind调用可以给session绑定uid
    • 通过FrontendSession访问session的只读字段,不过对FrontendSession中与session中相同的只读字段的修改并不会反映到原始的session中。

    服务 service

    Pomelo框架有两个service服务:SessionService、BackendSessionService

    SessionService维护所有的原始session信息,包括不可访问的字段,绑定的uid以及用户自定义的字段。

    BackendSession与FrontendSession类似,BackendSession是用于后端服务器的,可以看作是原始session的代理,其数据字段跟FrontendSession基本一致。

    BackendSession是由BackendSessionService创建并维护的,在后端服务器接收到请求后,由BackendSessionService根据前端服务器RPC的参数进行创建。

    对BackendSessionService的每次方法调用实际上都会生成一个远程过程调用,比如通过一个sid获取其BackendSession。同样对于BackendSession中字段的修改也不会反映到原始的session中,不过与FrontendSession一样,BackendSession也有push、bind、unbind调用,它们的作用与FrontendSession一样都是用来修改原始中的settings字段或绑定/解绑uid的,不同的是BackendSession的这些调用实际上都是namespace为sys的远程调用。

    频道 Channel

    channel可以看作是玩家ID的容器,主要用于需要广播推送消息的场景。

    可以把玩家加入到一个channel中,当对这个channel推送消息时,所有加入到这个channel的玩家都会受到推送过来的消息。

    一个玩家的ID可能会加入多个channel中,这样玩家就会受到其加入的channel推送过来的消息。

    需要注意的时channel都时服务器本地的,应用服务器A和B并不会共享channel,也就时说在服务器A上创建的channel只能 由服务器A才能给它推送消息。

    消息类型 request response notify push

    Pomelo中有四种消息类型的消息分别是requestresponsenotifypush

    • 客户端发起request请求到服务器,服务器处理后返回response响应。
    • notify是客户端发给服务器的通知,也就是不需要服务器给与回复的请求。
    • push是服务器主动给客户端推送消息的类型

    过滤器 filter

    filter分为beforeafter两类,每个filter都可以注册多个形成一个filter链,所有客户端请求都会经过filter链进行处理。

    • before filter会对请求做一些前置处理,如检查当前玩家是否已经登录,打印统计日志等。
    • after filter是进行请求后置处理的地方,比如释放请求上下文的资源,记录请求总耗时等。
    • after filter中不应该再出现修改响应内容的代码,因为在进入after filter前响应就已经被发送给客户端。

    处理器 handler

    handler是实现具体业务逻辑的地方,在请求处理流程中,handler位于before filterafter filter之间。

    handler的接口声明:

    handler.methodName = function(msg, session, next){
      //...
    }
    

    after filter的参数含义和before filter类似,handler处理完毕后,如果需要返回给客户端响应,可以将返回结果封装成JavaScript对象,通过next传递给后续流程。

    展开全文
  • pomelo

    2019-05-28 12:34:00
    pomelo pomelo架构概览 pomelo之所以简单易用、功能全面,并且具有高可扩展性、可伸缩性等特点,这与它的技术选型和方案设计是密不可分的。在研究大量游戏引擎设计思路基础上,...

    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

    posted @ 2019-05-28 12:34 00000000O 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • pomelo插件

    2019-03-26 14:32:38
    为了方便开发者根据自身的需求对pomelo原有的功能进行有效的扩展,pomelo在0.6版本提供了一种灵活的插件机制。 Plugins 在pomelo 0.6版中,已开发完成组件包括:pomelo-sync-plugin,pomelo-globalchannel-plugin...

    为了方便开发者根据自身的需求对pomelo原有的功能进行有效的扩展,pomelo在0.6版本提供了一种灵活的插件机制。

    Plugins

    在pomelo 0.6版中,已开发完成组件包括:pomelo-sync-pluginpomelo-globalchannel-pluginpomelo-status-pluginpomelo-masterha-plugin;另外可以参考使用插件机制完成的 chatofpomelo-plugins

    结构

    插件的结构主要包括两个部分:components和events,其中components是必要的,events则可以根据插件自身所需功能进行配置。如下图所示:

    在这里插入图片描述

    components跟pomelo中原有的组件功能一致,具体可以参考 pomelo 组件。它是服务器生命周期的服务单元,一个组件负责实现一类具体的功能。在plugin中开发者可以根据需要定义多个组件,开发者可以根据需要实现服务器不同生命周期的回调方法,包括start、afterStart、stop三个生命周期过程。

    events是为了开发者可以对pomelo中基本事件进行处理,开发者可以根据自身的需求对不同的事件进行监听并作出相应的处理。现在主要包括add_servers、remove_servers、replace_servers、bind_session、close_session。

    • add_servers:系统添加服务器事件,参数为添加的服务器信息,参数类型是数组。
    • remove_servers: 系统移除服务器事件,参数为移除的服务器信息,参数类型是数组。
    • replace_servers: 系统中有(除master)的服务器断网后重新连接事件,参数为断网的服务器收到系统中现存服务器信息,参数类型是数组。
    • bind_session: 系统中有用户进行session绑定操作事件,参数为session对象。
    • close_session: 系统中有用户session关闭事件(包括连接断开和连接异常),参数为session对象。

    使用方法

    pomelo中使用plugin的相应API如下:

    API

    app.use(plugin, opts)

    使用相应的pomelo插件

    Arguments

    • plugin - plugin that uses in pomelo
    • opts - attach parameters

    pomelo中使用组件只需要在app.js中进行相应配置即可,具体可以参考如下代码:

    var statusPlugin = require('pomelo-status-plugin');
    
    app.use(statusPlugin, {
     status:{
      host: '127.0.0.1',
      port: 6379
     }
    });
    

    ps: 由于plugin中可以有多个component,所以相应的配置参数也可能为多个,为了区分不同组件的配置参数,在use方法的第二个参数中可以配置多个组件的配置参数,key为相应组件的文件名,value为配置参数。

    构建方法

    首先,需要创建一个符合plugin规范的空项目,具体的项目目录结构如下图所示:

    在这里插入图片描述

    其次,需要在index.js中进行相关配置,由于在plugin中components是必要的,所以必须在index.js中指明components的路径信息,events如果有用到可以进行配置,具体配置参考如下代码:

    module.exports = {
     components: __dirname + '/lib/components/',
     events: __dirname + '/lib/events/'
    };
    

    最后,就可以进行components和events中相关代码的编写。对于component,需要对外提供相应的构造函数,pomelo在加载过程中会将相应的服务器上下文信息和配置参数进行注入,具体可参考如下代码:

    module.exports = function(app, opts) {
     return new Component(app, opts);
    };
    
    var Component = function(app, opts) {
     //do construction
    };
    
    Component.prototype.start = function(cb) {
    // do something application start
    };
    
    Component.prototype.afterStart = function(cb) {
    // do something after application started
    };
    
    Component.prototype.stop = function(force, cb) {
    // do something on application stop
    };
    

    对于event, 同样需要对外提供其构造函数,pomelo会在加载过程中将相应服务器的上下文信息注入,开发者只需根据自身需要编写相应的回调函数即可,具体可参考如下代码:

    module.exports = function(app) {
     return new Event(app, opts);
    };
    
    var Event = function(app) {
     //do construction
    };
    
    Event.prototype.add_servers = function(servers) {
     //do something when application add servers
    };
    
    Event.prototype.remove_servers = function(ids) {
     //do something when application remove servers
    };
    
    Event.prototype.replace_servers = function(servers) {
     //do something when server reconnected
    };
    
    Event.prototype.bind_session = function(session) {
     //do something when session binded
    };
    
    Event.prototype.close_session = function(session) {
     //do something when session closed
    };
    
    展开全文
  • pomelo-cli 是 Pomelo 维护的命令行库。 标签:pomelo
  • Pomelo -- a fast, scalable game server framework for node.js Pomelo is a fast, scalable game server framework for node.js. It provides the basic development framework and many related components, ...
  • pomelo使用手册

    2018-01-03 12:18:55
    便携查询pomelo的api便携查询pomelo的api便携查询pomelo的api
  • pomelo-unityclient-socket 是 Pomelo 的 .NET 客户端,支持 Pomelo 0.3和新的交流协议,基于原生的 Socket。示例Unity3D demo dotnet demo API初始化using namespace Pomelo.DotNetClient string host=...
  • Pomelo Client

    2019-11-19 20:16:32
    使用pomelo做服务器开发时,无论什么客户端,只要遵循与服务器的线上协议就能够与服务器建立通信。pomelo内置sioconnector、hybirdconnector都定义了自己的协议格式。 服务器通信协议 配置服务器通信协议 $ vim game...
        

    使用pomelo做服务器开发时,无论什么客户端,只要遵循与服务器的线上协议就能够与服务器建立通信。pomelo内置sioconnector、hybirdconnector都定义了自己的协议格式。

    服务器通信协议

    配置服务器通信协议

    $ vim game-server/app.js
    
    const pomelo = require('pomelo');
    
    /**
     * 初始化应用
     */
    const app = pomelo.createApp();
    app.set('name', 'test');
    
    //前端服务器配置
    app.configure('production|development',  'connector', function(){
        //连接配置
        app.set('connectorConfig',
        {
          connector : pomelo.connectors.hybridconnector,
          heartbeat : 3,
          useDict : true,
          useProtobuf : true
        });
    });
    
    //开启应用
    app.start();
    
    process.on('uncaughtException', function (err) {
      console.error(' Caught exception: ' + err.stack);
    });
    
    

    Pomelo支持的通信协议

    在与客户端通信时pomelo提供了hybirdconnector和sioconnector,hybirdconnector支持TCP、WebSocket,sioconnector支持socket.io。实际编程中,可使用pomelo提供的接口自定义connector。

    前端服务器 协议 通信 适用范围
    hybirdconnector pomelo.connectors.hybirdconnector TCP、WebSocket 使用二进制通信 移动端
    sioconnector pomelo.connectors.sioconnector socket.io 使用JSON通信 PC端
    udpconnector pomelo.connectors.udpconnector UDP 二进制协议 网路环境差数据包小的环境
    mqttconnector pomelo.connectors.mqttconnector MQTT 二进制物联网协议 嵌入式设备

    pomelo内部有各种协议的实现,典型的有protobuf、mqtt。mqtt物联网协议的特点是体积小、效率高、省电,pomelo+mqtt能实现单机30w在线的推送。

    Web端API

    Web端JavaScript开发库

    对于浏览器来说,HTML5中已经支持了WebSocket,因此使用支持WebSocket的浏览器可以直接与服务器的hybirdconnector建立通信。对于比较旧的浏览器,还没有支持websocket的可使用基于socket.io的方式与服务器建立连接。因此,对于Web端,Pomelo提供了两套开发库,分别适用于支持WebSocket的浏览器和不支持WebSocket的浏览器。

    开发库 描述
    pomelo-jsclient-socket.io 适用于socket.io
    pomelo-jsclient-websocket 适用于websocket

    无论是socket.io还是websocket都提供了统一的API

    初始化

    pomelo.init(params, cb);
    

    客户端pomelo初始化,在客户端第一次调用时使用。参数params中需要指定连接的服务器的主机地址和端口,回调函数cb在连接成功后会进行回调。

    pomelo.init = function(params, cb){
      pomelo.params = params;
      params.debug = true;
      var host = params.host;
      var port = params.port;
    
      var url = 'ws://' + host;
      if(port) {
        url +=  ':' + port;
      }
    
      socket = io(url, {'force new connection': true, reconnect: false});
    
      socket.on('connect', function(){
        console.log('[pomeloclient.init] websocket connected!');
        if (cb) {
          cb(socket);
        }
      });
    
      socket.on('reconnect', function() {
        console.log('reconnect');
      });
    
      socket.on('message', function(data){
        if(typeof data === 'string') {
          data = JSON.parse(data);
        }
        if(data instanceof Array) {
          processMessageBatch(pomelo, data);
        } else {
          processMessage(pomelo, data);
        }
      });
    
      socket.on('error', function(err) {
        console.log(err);
      });
    
      socket.on('disconnect', function(reason) {
        pomelo.emit('disconnect', reason);
      });
    };
    

    请求服务

    pomelo.request(route, msg, cb);
    

    request用于请求服务,route是服务端的路由,格式为"xxx.xxx.xxx"。msg为请求内容,cb响应回来后的回调函数。

    参数 描述
    route 服务端的路由,格式为"xxx.xxx.xxx"。
    msg 请求内容
    cb 响应成功后的回调函数
    pomelo.request = function(route) {
      if(!route) {
        return;
      }
      var msg = {};
      var cb;
      arguments = Array.prototype.slice.apply(arguments);
      if(arguments.length === 2){
        if(typeof arguments[1] === 'function'){
          cb = arguments[1];
        }else if(typeof arguments[1] === 'object'){
          msg = arguments[1];
        }
      }else if(arguments.length === 3){
        msg = arguments[1];
        cb = arguments[2];
      }
      msg = filter(msg,route);
      id++; 
      callbacks[id] = cb;
      var sg = Protocol.encode(id,route,msg);
      socket.send(sg);
    };
    

    例如:同网关服务器建立连接后 ,向其发送查询前端服务器入口的请求。

    /**
     * 连接gate服务器
     * 客户端首先要给gate服务器查询一个connector服务器,gate给其回复一个connector的地址及端口号
     * */
    function queryEntry(data, callback){
        const config = {host:"127.0.0.1", port:3014, log:true};
        pomelo.init(config, function(socket){
            const route = "gate.gateHandler.queryEntry";
            pomelo.request(route, data, function(msg){
                pomelo.disconnect();
                if(!msg){
                    msg = {code:500, msg:"error"};
                }
                callback(msg);
            });
        });
    }
    

    主动断开连接

    pomelo.disconnect();
    

    disconnect()方法用于Pomelo主动断开连接

    pomelo.disconnect = function() {
      if(socket) {
        socket.disconnect();
        socket = null;
      }
    };
    

    从EventEmmiter继承过来的方法

    on()方法用于从EventEmmiter继承过来,用来对服务端的推送做出响应。route用户可以自定义,格式一般为onXXX

    pomelo.on(route, cb);
    
    EventEmitter.prototype.on = EventEmitter.prototype.addListener;
    

    例如:

    //消息监听
    pomelo.on("disconnect", function(msg){
        console.log("disconnect", msg);
    });
    
    展开全文
  • Pomelo Application

    2020-04-03 17:16:13
    应用程序配置,如何配置Pomelo框架? Pomelo可以配置各个组件的选项,加载配置文件,开启Pomelo的特性等,这些配置都是在game-server/app.js文件中进行的。实际上在Pomelo的应用中有两个app.js,一个是在game-...
  • Pomelo App

    2019-11-20 11:14:34
    应用程序配置,如何配置Pomelo框架? Pomelo可以配置各个组件的选项,加载配置文件,开启Pomelo的特性等,这些配置都是在game-server/app.js文件中进行的。实际上在Pomelo的应用中有两个app.js,一个是在game-server...
  • Pomelo Command

    2019-11-22 11:56:21
    $ pomelo start -e development|production 启动时以production产品模式下运行则必须添加--deamon选项以后台守护进程方式运行,否则会出现master、gate等服务器消失的情况。 $ pomelo start -e production --deamon...
  • pomelo解说

    千次阅读 2018-05-23 12:20:00
    nodejs+pomelo+mysql实战经验分享Pomelo我的仓库地址Overview介绍pomelo 是一个与以往单进程的游戏框架不同,拥有高性能,高可伸缩性,分布式多进程的游戏服务器框架。Easy configure , Easy use!它包括基础开发框架...
  • Pomelo Message

    2019-11-21 10:19:16
    Pomelo中有四种消息类型的消息,分别是request、response、notify、push。 Pomelo客户端和服务器之间的通讯方式分为三种形式 request/response请求响应是一组,由服务器接收客户端request请求,处理完逻辑后做出...
  • Pomelo Connector

    2019-11-16 21:21:39
    pomelo是按约定来编程的,是微内核+插件实现方式。按照网络服务器流程,首先需要监听、绑定主机和端口,才有连接进来,连接建立后才有数据收发和编码解码。 connector是Pomelo的一个组件,俗称前端服务器。connector...
  • pomelo命令行管理pomelo项目

    千次阅读 2016-03-22 14:47:21
    1,pomelo的启动 pomelo start -e development | production 这个没什么问题 2,查看服务器 pomelo list -p port (这个地方,后面端口必须是master的端口,必须与你项目里config里master的配置一致,还有-p有时候...
  • pomelo服务器管理工具

    2019-08-12 04:53:01
    pomelo服务器管理工具
  • Pomelo Heartbeat

    2019-12-23 07:37:25
    Pomelo客户端握手 Pomelo在init初始化时会创建WebSocket连接,并定义onopen和onmessage事件回调。当连接建立后,onopen被回调。客户端首先会发起握手数据包: var obj = Package.encode( Package.TYPE_HANDSHAKE, ...
  • Pomelo Config

    2019-12-13 10:56:40
    pomelo服务端game-server下的config文件夹用于存放配置文件,包括pomelo框架的配置文件、第三方插件的配置文件、用户自定义的配置文件。其中默认的配置文件包括: 配置文件 描述 master.json Master主服务器...
  • Pomelo Component

    2019-11-21 12:56:48
    Pomelo总体架构 Pomelo的App Server规范中指出servers包下每个服务器子包下的每个文件均为一个module模块,module中export方法可被分派请求的method方法。 例如:聊天服务下包含三个文件夹分别是filter过滤器、...
  • quick-pomelo 是网易 Pomelo 游戏框架深度优化版。高性能和可伸缩快速内存数据访问分布式架构,系统可以水平扩展 分布式 ACID 事务在分布式环境支持 ACID(Stands for Atomicity, Consistency, Isolation, Durability...
  • Pomelo PRC

    2019-11-21 19:36:25
    pomelo采用多进程的架构实现游戏服务器进程的扩展以达到支撑较多的用户,降低服务器压力等要求。进程间通信采用RPC的形式完成。 服务器间RPC调用的抽象 pomelo架构中各个服务器之间的通讯主要是通过底层RPC框架来...
  • Pomelo Structure

    2019-11-16 21:21:50
    Pomelo是游戏服务器框架,本质上也是高实时、高扩展、多进程的应用框架,除了在提供的库部分有游戏专用的库,其余部分框架完全可用于开发高实时的应用。而且与现有的Node.js高实时应用框架如Derby、Socketstream、...
  • 搭建pomelo 开发环境

    2020-09-04 10:01:32
    Pomelo是基于 Node.js 的高性能、分布式游戏服务器框架。它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发。Pomelo不但适用于游戏服务器开发,也可...
  • 新版本的pomelo里增强了支持用户自行扩展的能力。用户只用在app.use(plugin, opts)就可以了,具体请看pomelo的application.js里的use函数。需要这个plugin里有components成员。use函数里,pomelo将plugin的componets...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,151
精华内容 860
关键字:

pomelo