集群实现细节(1)-异服通信和压测
背景
项目开始后,先敲定了大体可横向扩展的集群架构(这是个美好的期望),然后开始编写单进程的服务器底层和逻辑,让前边几个迭代周期的逻辑内容配合客户端跑起来了。
接着就是将单进程的架构扩展起来,设计上细化下架构的扩展。已写在前篇《休闲手游服务器集群扩展思考》里。最近的两周在将之前单进程的服务器架构里部分模块扩展为支持这篇随笔里提到的集群架构。
实现的过程中碰到的一些需要仔细设计的细节,原则上还是 K.I.S.S。
全服玩家在线状态
逻辑服务器集群的负载均衡算法还没实现。先只扩展玩家间的同服通信为异服通信(通过 Redis 的 pub/sub,以下将这个用于通信转发的 Redis 简称为通信 Redis)。
问题链:(“–>>”引出的下个问题被当前问题所依赖)
- 通信发起方需要知道目标方在逻辑集群里的哪个服务器上 –>>
- 玩家登陆和退出时往通信redis报告 –>>
- 登陆时检查账号是否注册到我们的游戏,否就注册 –>>
登陆和注册
玩家拿到用户系统的账号来登陆我们游戏服务器。游戏服务器拿 Client 给的这个 code 再去用户系统服务器做验证,通过后继续。
检查账号是否在我们游戏注册,如果没有则注册上,映射出游戏服务器上的一个 local uid。这里需要检查玩家是否在游戏注册了,所以需要一个 platform uid 与 local uid 的映射表。这个映射之前单进程服务器时与其他角色数据放在相同 Redis 上的,现在移到全局类的 Redis 上(以下简称全局 Redis,暂时是将通信 Redis 和全局 Redis 放一起的,等以后看压测和线上反馈再做演变)。另外用来本地注册生成 local uid 的自增长 ID 也移到了全局 Redis 上。
检查完注册,得到 local uid,先看是否在本服务器登陆了,否则再向通信 Redis 查看是否登陆在其他服务器。如果已登陆,则踢掉之前的登陆。之前单进程只有同服重复登陆踢人,现在多个异服重复登陆的踢人操作。
登陆成功向通信 Redis 报告 local uid 和所在的这个 logic 服务器的 Server ID。另外退出时也向通信 Redis 报告,注销掉这条记录。
异服通信
每个逻辑服务器都与通信 Redis 建立用于 pub/sub 的链接,各逻辑服务器有自己的频道。
异服上的玩家通信时,从通信 Redis 拿到目标玩家所在 Server ID,让后向目标 Server所对应的专有频道 pub 数据即可。
压测工具
加了这个集群扩展后,底层测试只是单元测试是不够的。反正要压力测试工具迟早要写,就先写了简单版的压测工具,来做异服通信的自动化测试。
压测工具开始的想法挺多的,后来抛弃了一些短期不好实现的想法。现在就简单的,一个 Client 一个 Client struct
,这个处理 Client 的通信发送接收。做相同动作的 Client 为一个 Group struct
。每个动作为一个 Rule struct
,里边组合好收到什么包后做什么事情,或者直接发些什么包。
C++ 端游压测的每个 Rule 动作一般用 Lua 来写的,比较方便,我们这个压测工具用 Go 写,Rule 暂时也用 Go 写,也不麻烦。
感慨下,这种并行的应用场景,Go 的编程思维与具体写法比 Node.js 更适合 C/C++ 出身的程序员。