3.2 方案设计
要支持数以万计的在线玩家,必然要采取分布式的设计方案。本节会介绍一种通用的分布式服务端架构方案。如果读者没有服务端开发的经验,阅读时可能会稍微有些吃力,不过没关系,先了解思路,后面进一步学习。
3.2.1 拓扑结构
我们设计了如图3-3所示的服务端结构,其中圆圈代表服务,圈内文字指明服务的类型和编号,比如“gateway1”代表“gateway”类型的1号服务。此服务端结构有如下特点:
·可以支持多个节点横向拓展。理论上,只要开启更多节点,就能够支持更多玩家。
·符合Skynet设计理念。每个服务都是轻量级的,功能单一,通过多个服务协作完成服务端功能。
在图3-3中,每个节点被划分成两部分,其中,用虚线方框围起来的称为“本地”服务,方框外的称为“全局”服务,它们的具体区别如表3-1所示。
图3-3 服务端拓扑结构设计图
表3-1 图3-3中本地服务和全局服务的区别
3.2.2 各服务功能
服务端包含了gateway、login等多个类型的服务,它们的功能如表3-2所示。
表3-2 各种服务的功能
3.2.3 消息流程
从客户端发起连接开始,服务端内部的消息处理流程如图3-4所示(这是个简化图,忽略了nodemgr)。
图3-4 服务端消息处理流程
登录过程:在阶段①客户端连接某个gateway,然后发送登录协议。gateway将登录协议转发给login(阶段②),校验账号后,由agentmgr创建与客户端对应的agent(阶段③和④)完成登录。如果该玩家已在其他节点登录,agentmgr会先把另一个客户端顶下线。
游戏过程:登录成功后,客户端的消息经由gateway转发给对应的agent(阶段⑤),agent会处理角色的个人功能,比如购买装备、查看成就等。当客户端发送“开始比赛”的协议时,程序会选择一个场景服务器,让它和agent关联,处理一场战斗(阶段⑥)。
3.2.4 设计要点
1.gateway
这套服务端系统采用传统C++服务器的架构方案。gateway只做消息转发,启用gateway服务有以下好处:
·隔离客户端与服务端系统。如果要更改客户端协议(比如改用json协议或protobuf),仅需更改gateway,不会对系统内部产生影响。
·预留了断线重连功能,如果客户端掉线,仅影响到gateway(下一章介绍)。
然而引入gateway意味着客户端消息需经过一层转发,会带来一定的延迟。将同一个客户端连接的gateway、login、agent置于同一节点,有助于减少延迟。
2.agent和scene的关系
agent可以和任意一个scene通信,但跨节点通信的开销较大(见1.4.2节)。一个节点可以支撑数千名玩家,足以支撑各种段位的匹配,玩家应尽可能地进入同一节点的战斗场景服务器(scene)。
3.agentmgr
agentmgr仅记录agent的状态、处理玩家登录、登出功能,所有对它的访问都以玩家id为索引。它是个单点,但很容易拓展成分布式。