HTML5技术

游戏服务端究竟解决了什么问题? - fingerpass(5)

字号+ 作者:H5之家 来源:H5之家 2016-02-02 09:51 我要评论( )

RabbitMQ提供了消息队列中间件能提供的所有基本语义,比如消息的ack机制和confirm机制、qos保证、各种pattern的支持、权限控制、集群、高可用、甚至是现成的图形化监控等等。接下来的讨论会尽量不涉及RabbitMQ具体

  RabbitMQ提供了消息队列中间件能提供的所有基本语义,比如消息的ack机制和confirm机制、qos保证、各种pattern的支持、权限控制、集群、高可用、甚至是现成的图形化监控等等。接下来的讨论会尽量不涉及RabbitMQ具体细节,把它当做一个通常的消息队列中间件来集成到我们目前为止形成的游戏服务端之中。当然,Gate经过扩展之后也能替代MQ,但是这样就失去了其作为Gate的意义——Gate更多的是用在性能敏感的场合,比如移动同步,协议太重是没有必要的。而且,重新造个MQ的轮子,说实话意义真的不大。

MQ解决了什么问题?

  MQ与Gate的定位类似,都是整个生态中的static parts。但是MQ与Gate是两种不同的基础设施抽象,提供的语义也不尽相同。

  • Gate要解决的问题是以最低的成本构建消息流模型,仅提供传输层所能提供的消息送到质量保证(TCP撕UDP暂时领先)。client与Gate的连接断开,Gate没有义务再保留连接上下文。Gate其实是在游戏场景同步需求情景下诞生的特殊的MQ,具有一部分MQ的职责,比如发布订阅(客户端发布,服务端订阅,带组播的话还支持message dup),协议高度简化(对比下AMQP协议的复杂度。。),没有一些MQ专有的capability(qos保证,消息持久化等)。
  • MQ要解决的问题是提供普适的消息队列抽象。性能不敏感的服务可以依赖MQ构建,将自己的连接维护与会话保持两块状态寄存在MQ上。
  •   这样,我们的服务端中就出现了两个static parts——一个是Gate,一个是MQ。Gate与MQ是两个完全无关的基础设施,这两部分先于其他所有dynamic parts启动、构建。场景服务连接Gate与MQ(前提是确实有其他服务会与场景服务进行通信),聊天服务连接MQ,client连接Gate与MQ。

     

      引入MQ之后的拓扑:

      再脑补一下,增加N个节点,就形成了Gate和MQ的双中心,网络拓扑优雅了很多。

      就具体实现来说,之所以选择RabbitMQ,还因为其对mqtt协议支持的比较好,官网上就有插件下载。mqtt协议可以参考这里。client走mqtt协议跟MQ通信还是比较轻量级的。

    引入新的问题

      现在,client或者服务都需要通过不同的协议(Gate、MQ)与其他部分通信。

      这样对应用层开发者来说就是一个负担。

  • 服务端和客户端,走Gate的流程都是基于私有协议与自有的API。
  • 同时,在客户端,走MQ的流程基于mqtt协议与mqttLib的API;在服务端,走MQ的流程基于amqp协议与rabbitMQ的API。
  •   ps. Gate的私有协议和mqtt、amqp协议下面会统称为消息路由协议。

      而且不同的API的调用模型都不一样,因此我们需要一种应用层统一的调用规范。

     

    3.3 游戏服务端中的RPC与Pattern

     

    3.3.1 RPC

     

    定义问题

      整理一下现状。

      目前,client可以发送两类消息:一类交由Gate路由,一类交由MQ路由。service也可以接收两类消息:一类由Gate路由过来,一类由MQ路由过来。

      

      我们希望的是,应用层只需要关心服务,也就是说发送的消息是希望转到哪个服务上,以及接收的消息是请求自己提供的哪个服务。
      这样对于应用层来说,其看到的协议应该是统一的,而至于应用层协议的底层协议是Gate的协议还是MQ的协议,由具体的适配器(Adaptor)适配。
      

      这个应用层的协议就是RPC的一部分。
      RPC一直都是很有争议的。一方面,它能让代码看起来更优雅,省了不少打解包的重复代码;另一方面,程序员能调RPC了,系统就变得很不可控,特别是像某些架构下面RPC底层会绕很多,最后用的时候完全违背设计本意。

       但是总的来说,RPC的优势还是比较明显的,毕竟游戏服务端的整体服务定义都是同一个项目组内做的,副作用严格可控,很少会出现调用一条RPC要绕很多个节点的情况。

    RPC解决什么样的问题?

      RPC的定位是具体消息路由协议与应用层函数调用的中间层。一个标准的RPC框架要解决两个问题:

  • 第一是协议定义。
  • 第二是调用规范的确立。
  •    RPC的协议定义也可以做个划分:

  • 协议中的一部分用来标识一次调用session,可以用来实现RPC的回调,可以用来实现RPC的超时管理等等。
  • 另一部分用来标识调用的具体方法。这部分其实跟用不用RPC没太大关系,因为不用RPC只是打解包的话也是会用一些协议序列化、反序列化协议包的。采用RPC框架的话,就是希望这部分工作尽可能多的自动化。
  •   RPC调用规范的核心设计意图就是让应用层程序员调用起来非常自然、不需要有太多包袱(类bigworld架构的rpc设计通常也是这个原则,尽量让应用层不关注切进程的细节)。调用规范的具体细节就跟语言和平台相关了。在支持异步语法的语言/平台,可以原生集成异步等待、执行完恢复上下文继续执行的语义。在不支持异步语法的语言/平台,那就只能callback。如果是不支持将函数作为参数传递的语言/平台,我想你应该已经离现代游戏开发太远了。

     

      通用的部分确定之后,还得解决特定于具体路由方式的、需要适配的部分。

      我将这部分逻辑称为Adaptor,很好理解,就是RPC到具体消息路由协议、具体消息路由协议到RPC的适配器。


      下面,结合一种具体的RPC实现方式(下文称为Phial规范),来探讨下如何将上面提出的这几个概念串起来。

     

      先通过一个大概的流程来厘清一次RPC流程中涉及的所有角色。

      RPC既然作为一次远程过程调用,那么,对于调用方来说,其调用的是一个跟普通函数很像的函数(有可能表现为一个异步函数,也有可能表现为一个同步函数);对于被调用方来说,其被调用的就真的是自己的一个函数了。

      整个的pipeline也很清晰:

  • 调用方调用某个服务的某个函数,RPC层会根据之前说的RPC层协议将调用信息(invokeId、方法id、参数等)打包,并将打包的消息和函数对应服务的路由规则告诉路由适配层,路由适配层根据路由规则给打包消息加个消息头,然后传给路由层(具体的Gate路由或MQ路由)。
  • 路由层将消息路由到对应节点,该节点上的路由适配层解出消息头和打包消息,根据消息头确定被请求服务,并这些信息传给RPC层,RPC层解打包消息得到调用信息,然后做一次dispatch,被调用方的一开始注册进来的对应函数就会被回调到了。
  •  

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 网页版扫雷游戏 - 季末的寂寞

      网页版扫雷游戏 - 季末的寂寞

      2017-04-21 13:00

    • net.sz.framework 框架 登录服务器架构 单服2 万 TPS(QPS) - 失足程序员

      net.sz.framework 框架 登录服务器架构 单服2 万 TPS(QPS) - 失足

      2017-04-13 11:05

    • 面向个人的技术咨询服务 - 思想瞭望者

      面向个人的技术咨询服务 - 思想瞭望者

      2017-04-05 12:07

    • net.sz.framework 框架 轻松搭建服务---让你更专注逻辑功能---初探 - 失足程序员

      net.sz.framework 框架 轻松搭建服务---让你更专注逻辑功能---初探 -

      2017-04-02 10:11

    网友点评