浅析分布式游戏架构

浅析分布式游戏架构

关键字

  • 集群
  • 高可用
  • 一致性

正文

  • 分布式架构需求

做游戏开发有几年了:(,在这个时间段一直使用java进行游戏逻辑功能的开发,以单服架构写逻辑居多。近几年:),游戏发展的速度很快,用户对体验要求越来越高。从客户端来说玩家对游戏美术的审美有所提高 。从服务器来说,单服架构承载人数有限,已经无法支持大型对战游戏,使用分布式架构,才能支持更多玩家在线的交互。

  • 分布式架构解决的问题
    • 提升服务可用性
    • 提高服务器承载能力
    • 动态扩展节点
  • 分布架构实例分析
    • 架构图如下

    • 节点说明

      • 平台 ,指第三方平台,暴露给玩家的http服务,主要做验证以及获取平台的相应信息。进入游戏,首先得经过第三方平台(或内部平台)验证。如果,存在这个用户时,则会请求服务器列表,反之,会请求创建用户。选服列表是通常游戏研发方,提供的一个服务,这个服务应该是高可用的,否则,这个服务的进程宕掉,将会导致玩家无法进入游戏。选择服务器后,开始进入登录服,会向登陆服传入游戏服务器id、平台类型、平台id等参数。
      • 登录服务器,暴露给玩家的服务,主要用于给玩家选择合适的逻辑服与网关服务。登陆服器是集群的,负载均衡器,可以由客户端随机选择,这是最简单的,为了真正的均衡,可以使用nginx去做,选择相应的均衡策略。为了防止玩家直接跨过平台节点,进入登录服,登录这边其实也要验证这个玩家是否已经被平台验证过。这个验证可以由登录服主动去请求平台的接口,来验证这个用户是否登录过,这个验证的过程通常是发http协议,这个过程是同步的,登录服务器需要等待平台的返回,才能执行下一步逻辑,所以性能压测这是一个优化的点。也可以由平台主动通知派发一个验证事件给登录服务器,这种方式可能会出现数据不一致的情况,因为平台方这个事件的通知是在网络中传输,无法保证登录服务器是先收到玩家的进入登录服的请求,还是先收到平台的验证事件,如果登录服是集群的话,要把这个事件通知所有的登录服务器,就会很麻烦,经过分析还是用第一种方式较为妥当:)。还有,登录服务器会主动连接 DCS,登陆服收到DCS处理的登陆结果后,向客户端返回网关服务器的ip与登陆密钥。
      • Data Consistency Server(DCS,瞎取的,毕竟名字不影响服务器性能:( ),对玩家隐藏的服务,这个服务器的名字,不知道咋取好一点,本意是这个进程是用来做数据一致性的。一个DCS与游戏服(玩家选服列表看到的一个条目,后面不做解释:))的对应关系可以是一对一,也可以是一对多,因为DCS做的事情足够简单,应该不会存在性能问题,性能存在问题,那就一对一吧:)。举一个数据一致性的场景:由于登录服务器、网关服务器、逻辑服务器是集群的,玩家连续发N个登录请求,可能同时进入多个登录服,多个登录服同时验证成功,就会有多个玩家进入游戏服,这样的很明显,结果是可能会有点刺激。当然,有了DCS,这个刺激的情况,就出现不了了.DCS保证同一个玩家,在多个登录服验证通过后,只有一个玩家进入游戏服,保证数据最终的一致性,DCS不关心有多少玩家进入登录服且验证成功。然后,DCS会往网关服务器注册玩家的选服(网关服务器、逻辑服务器)信息,防止玩家直接跳过登陆环节与不进入指定的网关服务器,并且在指定的时间内,玩家还是进入这次选择的服务器。最后向登陆服返回网关服务器的ip与登陆密钥。另外,网关、逻辑服务器的信息,是从zookeeper获取的。
      • 网关服务器,处理客户端与逻辑服之间的消息转发、gate的验证、无效请求的过滤,暴露给玩家的进程。玩家进入网关服务器,会传入一个密钥参数,根据这个参数获取当前玩家选服信息,如果不存在,则此次登陆失败。选服信息里包括逻辑服务器id,根据这个id,会去连接相应的逻辑服务器。当前,网关服务器是集群的,网关服务器启动时,会主动连接所有逻辑服务器,对应关系是1对多,也会向zookeeper注册当前服务器的信息并且定时更新当前服务器信息。后面玩家的交互,是通过网关服务器将玩家请求转发给逻辑服务器,逻辑服处理相关请求后,将结果返回给网关服务器,网关服务器再将返回的结果,转发个客户端。两个进程的socket连接,要考虑谁主动连接谁更合适,重连是一个考虑点。
      • 逻辑服务器,处理玩家的业务逻辑。逻辑服务器是集群的,在启动的时候,会向zookeeper主动注册当前服务器的信息并且定时更新当前服务器信息。由于集群,玩家与玩家之间的交互变的有点麻烦,一种方式是逻辑服务器之间相互连接,另一种方式是所有逻辑服务器向公共服务器注册,由公共服务器管理所有逻辑服务器的连接,有了逻辑服的连接就可以转发玩家与玩家之间的消息。逻辑服与数据库交互频繁,为了减少网络、磁盘的IO会引入缓存,缓存通常是会有本地缓存与远程缓存。比如,玩家登进行录下线、登录下线、登录下线、登录下线的行为,每次数据都从db获取,同时在线玩家很多的时候,这样将导致用户体验变差。使用缓存,可以在指定时间内,玩家的数据常驻缓存,无需从db获取,玩家下线后过了指定时间,再去清除缓存,这样保证了玩家登录是流畅的。
      • 公共服务器,处理玩家与玩家之间的业务逻辑。
      • zookeer,是一个集群,用于配置管理、服务器信息负载信息注册。配置管理,包括策划配置表、服务器信息配置(比如端口、服务器名等等)。由于zookeeper有事件通知机制,节点数据变化时,zookeeper会通知监听的客户端,客户端根据这些事件可以执行一些相应的逻辑,如启动一个新的网关服务器。
      • 数据库服务器,持久化数据,是一个进程。数据库服务器对外提供一些接口,有一个通用的sdk,可以理解为数据库服务器的客户端。所有的接口有两个必传的参数游戏服务器id、玩家id,这个两个参数用来分库分表,合服的时候也是用这个两个参数来获取自己的数据(合服的时候玩家列表,并不回合,服务器列表有几个条目还是几个条目)。一个数据库服务器可以连接多个db,如合服的时候,1、2、3、4、5、6合服了,那么数据库服务器可以连接到这6个db。sdk调用一个接口,传入serverid、玩家id就知道是哪个库、表了。合服的过程可以是动态的,且不用合数据库。公共、逻辑、网关服务器,合服同样也是一样,合服的关键点在服务器id,以及如何把多个服务器id,映射成一种关系,比如一个种合服的关系、一组服务器的关系(一个服务器对应哪些gate,logic等)。
      • 远程缓存,缓存常用数据。由于一份数据保存在多个进程,要明确哪个进程的数据是最新的,以及如何解决缓存带来一些常见的问题

集群与高可用

一个服务集群,解决了单节点挂掉,整个服务不可用的问题,提高了可用性。当然使用集群,是整个业务流程变的复杂。一个业务在一个单进程处理,步骤可能非常简单。但是,这个业务到了集群的环境后,就得考虑上文说的数据一致性,而且一个业务经过的节点越多,考虑的情况也就越多,因为这个业务可能在某个节点中断,如何保证一个业务的最终的正确性,在集群的应用场景变的非常重要。另外,一个节点挂掉与重启,要考虑数据的恢复,不然有可能会对整个业务有影响。

总结

这个架构,登陆、网关、逻辑服务器、redis、zookeeper支持集群,可以动态扩展,瓶颈在DCS、Common、DBServer,理论上做世界服是没问题。假设集群节点一次不会全部宕机,如果宕机了会影响一部分玩家,那么当前需要着重考虑的是DCS与Common、DBServer宕机。DCS如果宕机,那么新登陆的玩家将无法进入游戏,已进入游戏的玩家并不影响他们的体验。Common如果宕机,会影响公共服务器的功能,不会对登录与玩家的业务有影响.DBServer宕机,是最危险的。

以上只是个人见解,还有很多细节,无法在这里一一写出。如有用词不妥,欢迎指正。

JackLei
JackLei

我是真的不会修电脑