HTML5技术

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

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

游戏开发中,这种组件的名字也比较通用,通常叫Gate。 Gate解决了什么问题 首先,Gate作为server,可以接受clients的连接。这里就可以直接用我们上一节输出的网络库。同时,其可以接受服务端进程(之后简称backend

  游戏开发中,这种组件的名字也比较通用,通常叫Gate。

Gate解决了什么问题
  • 首先,Gate作为server,可以接受clients的连接。这里就可以直接用我们上一节输出的网络库。同时,其可以接受服务端进程(之后简称backend)的连接,保持通信。
  • 其次,Gate能够将clients的消息转发到对应的backend。与此对应的,backend可以向Gate订阅自己关注的client消息。对于场景服务来说,这里可以增加一个约束条件,那就是限制client的上行消息不会被dup,只会导到一个backend上。
  •   仅就这两点而言,Gate已经能够解决上一节末提出的需求。做法就是client给消息加head,其中的标记可以供Gate识别,然后将消息路由到对应的backend上。比如公会相关的消息,Gate会路由到全局进程;场景相关的消息,Gate会路由到订阅该client的场景进程。同时,玩家要切场景的时候,可以由特定的backend(比如同样由全局进程负责)调度,让不同的场景进程向Gate申请修改对client场景相关消息的订阅关系,以实现将玩家的entity从场景进程A切到场景进程B。

     

      站在比需求更高的层次来看Gate的意义的话,我们发现,现在clients不需要关注backends的细节,backends也不需要关注clients的细节,Gate成为这一pipeline中唯一的静态部分(static part)。

     

      当然,Gate能解决的还不止这些。

     

      我们考虑场景进程最常见的一种需求。玩家的移动在多client同步。具体的流程就是,client上来一个请求移动包,路由到场景进程后进行一些检查、处理,再推送一份数据给该玩家及附近所有玩家对应的clients。

      如果按之前说的,这个backend就得推送N份一样的数据到Gate,Gate再分别转给对应的clients。

      这时,就出现了对组播(multicast)的需求。

     

      组播是一种通用的message pattern,同样也是发布订阅模型的一种实现方式。就目前的需求来说,我们只需要为client维护组的概念,而不需要做inter-backend组播。

      这样,backend需要给多clients推送同样的数据时,只需要推送一份给Gate,Gate再自己dup就可以了——尽管带来的好处有限,但是还是能够一定程度降低内网流量。

     

      那接下来就介绍一种Gate的实现。

     

      我们目前所得出的Gate模型其实包括两个组件:

  • 针对路由client消息的需求,这个组件叫Broker。Broker的定义可以参考zguide对DEALER+ROUTER pattern的介绍。Broker的工作就是将client的消息导向对应的backend。
  • 针对组播backend消息的需求,这个组件叫Multicast。简单来说就是维护一个组id到clientIdList的映射。
  •  

      Gate的工作流程就是,listen两个端口,一个接受外网clients连接,一个接受内网backends连接。

      Gate有自己的协议,该协议基于Network的len+data协议之上构建。

      clients的协议处理组件与backends的协议处理组件不同,前者只处理部分协议(不会识别组控制相关协议,订阅协议)。

     

      在具体的实现细节上,判断一个client消息应该路由到哪个backend,需要至少两个信息:一个是clientId,一个是key。

      同一个clientId的消息有可能会路由到不同的backend上。

      当然,Gate的协议设计可以自由发挥,将clientId+key组成一个routingKey也是可以的。

     

      引入Gate之后的拓扑:

     

      具体代码请参考:GateSharp

    引入新的问题

      现在我们在需求的金字塔上更上了一层。之前我们是担心玩家数量增长会导致服务端进程爆掉,现在我们已经可以随意扩容backend进程,我们还可以通过额外实现的全局协调者进程来实现Gate的多开与动态扩容。甚至,我们可以通过构建额外的中间层,来实现服务端进程负载动态伸缩,比如像bigworld那样,在场景进程与Gate之间再隔离出一层玩家agent层。

     

      可以说,在这种方案成熟之后,程序员之间开始流行“游戏开发技术封闭”这种说法了。

     

      为什么?

     

      举一个简单的例子,大概描述下现在一个游戏项目的服务端生命周期状况:

      结果就是,产出了几个玩具水平的服务器进程。要非得说是工业级或者生产环境级别的吧,也算是,毕竟bugfix的代码的体量是玩具项目比不了的。而且,为了更好地bugfix,通常会引入lua或者python,然后游戏逻辑全盘由脚本构建,这下更方便bugfix了,还是hotfix的,那开发期就更能随便写写写了,你说架构是什么东西?

     

      至于具体拓扑,可以对着下图脑补一下,增加N个节点,N个节点之间互相连接。

     

      玩具水平的项目再修修补补,也永远不会变成工艺品。

     

      skynet别的不说,至少实现了一套轻量级的actor model,做服务分离更自然,服务间的拓扑一目了然,连接拓扑更是优雅。网易的mobile_server,说实话我真的看不出跟bigworld早期版本有什么区别,连接拓扑一塌糊涂,完全没有服务的概念,手游时代了强推这种架构,即使成了几款过亿流水又怎样?

     

      大网易的游戏开发应届生招聘要求精通分布式系统设计,就mobile_server写出来的玩具也好意思说是“分布式系统”?

     

      很多游戏服务端程序员,在游戏服务端开发生涯结束之前,其接触的,或者能接受的设计基本到此为止。如果是纯MMO手游,这样做没什么,毕竟十几年都这样过来了,开发成本更重要。更搞笑的是社交游戏、异步战斗的卡牌游戏也用mobile_server,真搞不明白怎么想的。

     

      大部分游戏服务端实现中,服务器进程是原子单位。进程与进程之间的消息流建立的成本很低,结果就是服务端中很多进程互相之间形成了O(n^2)的连接数量。

      这样的话会有什么问题?

      一方面,连接拓扑关系很复杂。一种治标不治本的方法是抬高添加新进程的成本,比如如非必要上面不会允许你增加额外进程,这样更深度的解耦合就成了幻想。

     

    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

    网友点评