最近工作上做了一些关于跨服玩法的内容,对于 RPC 通信实现这块做下学习笔记整理。
分布式架构
当下的大环境下,服务器架构基本都是分布式架构。分布式架构带来的最大好处在于服务扩展,我们 SLG 游戏服务器从游戏特性上来说,符合小服架构(一个服即一个生态),这样从分布式架构的设计理念,按功能划分,网关、支付、战场(这里不是指单服的战斗要实现一个节点,而是一些副本玩法,跨服玩法等设计的)、第三方等,这样的每个 server 我们称之为一个节点(Node)。
RPC
RPC:允许运行于一台计算机的程序调用另一个计算机的程序。RPC是一种服务器-客户端(Client/Server)模式。
RPC 的核心概念即调用远程服务就像调用本地的一个函数一样简单。
通过原理我们知道 RPC 需要实现的几个点:
- 通信:在两个 server 之间建立连接
- 寻址:如何定位需要调用 x-Server
- 序列化:两个 server 之间是网络通信,那么二进制传输就需要序列化
一些常用的框架(轮子必然是有的):
- gRPC: 谷歌开源 RPC 框架,基于 HTTP/2 协议通信和 ProtoBuf 序列化协议
- Thrift: Apache 旗下,基于 Facebook 的 RPC 框架开发
- JsonRPC: 无状态、轻量级,基于 json 序列化
框架选择:两个项目,早期的一个选择 thrift (当时 gRPC 才开源初期),另一个选择了 gRPC ,对比来说,两者在使用上区别不是很大,但是 gRPC 能拥有良好的文档,更加简洁和拥有广泛使用的 ProtoBuf,而 thrift 的大优势是支持多语言。选择根据项目自身的特性来,对于我们项目,文档和简洁比较重要。(技术选型还得是项目初始大佬们的选择:joy:)
节点间通信
如上,RPC 框架选择 gRPC,基于此,整个通信流程:
client -> gateway -> game server -> other server -> 处理后返回
游戏服务器一般选择长连接,因为游戏特性:交互频繁,数据量大。RPC 当然也有这种特性,所以 gRPC 也支持一次调用一次创建和流式(stream)调用两种方式,这个根据业务的情况进行处理。client 与 game server 的通信采用了双向 steam 方式,client 通过和 gate 建立 tcp 连接(一个 agent),然后通过 LoginReq 来创建和 game server 的流式管道(中间还有玩家信息验证服交互,目标服务器 check 等操作 | 目标服的 connect 信息通过 etcd 获取, etcd 做服务发现和管理),每个 agent 本身会有一个 pipe mgr 来管理这些创建的管道,用于和不同的 server 之间进行消息收发。这样就建立起 client <—> game server 的通信连接。
既然节点间的通信就是 client/server 的模式,那么 game server 和 battle server 之间的服务调用也就差别不大。以此为例,简述我们 gs 和 bs 之间的服务调用:
- 一次调用:gRPC Asyn Call 调用 bs 的服务器,通过异步回调返回执行的数据,并处理返还给 client
- steam: 每个 server 都有一个自己的 gate mgr 用于管理 RPC 消息通信和 agent data,首次调用 bs 服务时创建一个 steam 连接,后面调用直接 sendMsg
- 没有玩家 agent 的 stream 调用:每个 server 都创建一个 owner agent 并且在需要的时候和目标 server 之间建立一个 steam pipe,来完成多次调用
举例说明:
我现在有个副本玩法,需要开房间实现 pvp:
-> clientA 通过 loginBattleReq 创建和 bs 的 steam 连接,并且在 bs 开启一个房间
-> clientB 通过 joinBattleReq 同样创建一个 stream 连接,加入到 A 的房间
-> 然后 bs 房间业务逻辑执行,A vs B 战斗开始
-> SLG 的一个特性,不同于 moba 游戏玩法,这里业务上可能多个玩家要持续一段时间 pvp 获得积分,在结束时,玩家可能已经不在线,steam 和 agent 也销毁了,结算信息传递给 gs 就需要通过 owner agent 来实现了。由此,一个完整的节点通信模型就实现了。
总结
- 目前的这套架构实现比较简单,弱耦合单向依赖 gRPC call、强耦合双向依赖 stream,已经能满足当下的基本需求,其次在编码方面做了一些封装,对于开发人员来说比较方便。
- 当需求变化伴随节点细分变多,耦合变重,那么网络拓扑也会变成一个问题,这种情况下的 steam 就不能很好的胜任。