jdk8.github.io

游戏服务引擎

游戏服务端区别于互联网服务端,互联网后台多是由多个微服务组成,如登录,商品,订单,支付服务等,后台数据持久化存储在DB中,并利用缓存提高数据访问速度。

ECS(entity component system)

游戏服务端通常使用一种称为ECS的架构,每个entity代表一个对象,可以是玩家,NPC,也可以是服务。

为了支持entity之间进行RPC通信,entity有MailBox,由IP端口和EntityID确定,集群间的Entity通过MailBox进行RPC调用。

客户端存在一个和服务端对应的entity,称之为avatar,代表玩家。客户端和服务端通过KCP(可靠UDP)协议传输数据。

AvatarEntity

代表玩家,是所有玩家控制的Entity的父类

单服结构

下图为传统的单服结构,这里的单服并非单机,而是对应一组Gate,Game,GameManager组成的进程,每个进程都是单epoll线程。

在这里插入图片描述

服务发现

Game服务器通过GameManager发布自己的地址信息:Game服务启动之后都会注册自己到GameManager中,同时也会发送keep-alive给GameManager,因此Gate服务器可以通过GameManager得到所有Game服务器的地址。

客户端登陆

游戏开始流程

Entity迁移

让gate缓存转发消息,而不是让老的game服务器转发消息主要是希望保证消息的有序性。因为如果让老的game服务器转发消息,可能会出现gate服务器和老的game服务器同时在给新的game服务器发送客户端消息,容易出现消息乱序。

服务的实现

服务也是通过Entity实现的,可以指定某个服务有多少个shard(通过配置),调用时制定调用的方式:

多服结构

单服结构的缺点是所有游戏逻辑(登录,社交,排行,工会,匹配,战斗等)都在一个服上实现,比如5V5 moba游戏,一个进程能承载的最多战斗为4场,要想实现10万人同时战斗,那这个服至少要有2500个进程,会导致GameManager负载过高,单点成为瓶颈。

于是出现了多服结构,如下图所示是一个大厅服,一个中心服,N个战斗服的架构,每个服都是一个单服结构,每个服都有Hostnum作为唯一的ID。

每个服的启动配置中指定了hostnum和服的类型,大厅服和战斗服配置中还指定了中心服的hostnum,这样可以调用到中心服的服务。 在这里插入图片描述

大厅服

所有玩家都在一个大厅服上登录,在玩家看来,都是在一个服进行登陆。因为大厅服只负责战斗外的一些逻辑,不会无上限的扩展Game进程,所以单服可以承载大量的玩家,也可以扩展大厅服的数量。

中心服

多服结构中只存在一个中心服,负责全局的玩法,如跨服匹配等,也负责管理战斗服的资源,负载均衡等。

战斗服

只负责战斗逻辑,无状态,不依赖存储,可以动态的增删战斗服。战斗服的状态(多少个game进程,每个进程目前有多少个战斗)需要定时向中心服上报,这样中心服就可以全局感知有多少个战斗服,每个战斗服的负载(能安排多少个战斗,以及目前有多少个战斗正在进行)。

当玩家匹配完成后请求分配战斗资源:

HUB服

实现跨服调用的一组服务,只做消息转发。entity的mailbox新增了一个hostnum,hub服会根据hostnum将消息投递到目标entity所在的服。

多服登录流程 在这里插入图片描述