一、背景
项目开始后,先敲定了大体可横向扩展的集群架构(这是个美好的期望),然后开始编写单进程的服务器底层和逻辑,让前边几个迭代周期的逻辑内容配合客户端跑起来了。
接着就是将单进程的架构扩展起来,设计上细化下架构的扩展。已写在前篇《休闲手游服务器集群扩展思考》里。最近的两周在将之前单进程的服务器架构里部分模块扩展为支持这篇随笔里提到的集群架构。
实现的过程中碰到的一些需要仔细设计的细节,原则上还是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++出身的程序员。