【从零开始学Skynet】实战篇《球球大作战》(四):分布式登录系统
分布式登录系统就像一场精心编排的芭蕾舞,每个角色都要跳得精准而协调。首先,角色对象的创建与销毁,好比舞者上台和退场,必须井然有序。当一个小舞者(客户端)上台(连接)时,后台(服务端)得立即准备好他的服装(角色数据),而当他退场(掉线)时,还得帮他保存好服装的状态,以免弄脏了。
接下来,防止角色重复登录的问题,就像是剧场的入场管理。每个舞者(角色)只能有一个观众席(客户端)可以观看他的表演。如果有另一个观众(客户端)想买同一张票,必须先请现任观众离场。这里,"agentmgr"就是剧场的门口保安,严格检查入场券,确保不会有重复入场的情况发生。
完整的登录流程就像是一部复杂的电影,每个镜头(阶段)都需要不同部门的协作。从观众选座(gateway选择),到检票(login服务验证),再到后台准备服装(agent创建),每个环节都不能出错。而掉线登出则是电影结束后的退场,确保每个观众都能带着自己的东西离开,不让剧场留下任何痕迹。
在实际操作中,可能会遇到突发状况,比如前观众还没完全退场,新观众就抢着进场。这时候,"agentmgr"这位保安就得施展他的智慧,要么让新观众稍等,要么礼貌地请前观众加快步伐。这样的机制确保了剧场的秩序,也保障了每个观众的权益。
总之,分布式登录系统的设计不仅需要考虑正常流程,还得预见各种意外情况,确保系统的健壮性和用户体验的流畅性。就像一场完美的演出,观众们只看到华丽的表演,背后却是无数次精心的策划与协调。
处理玩家的登录,是服务端框架的主要功能之一。分布式系统涉及多个服务,让它们相互配合不产生冲突是一大难点。
1、登录流程
分布式服务端的登录功能要处理好如下两个问题:
- 问题一:完成角色对象的构建和销毁。如下图所示:
当客户端连接、发起登录时,服务端要创建一个对应角色的程序对象,用以加载角色数据。当客户端掉线时,服务端要保存角色数据,并销毁程序对象。这套框架会为每个客户端创建一个agent服务。
如何解决:需要创建名为agent的服务,它也代表角色对象。
- 问题二:防止角色重复登录。如下图所示:
在同一时间,一个角色只能由一个客户端控制,如果用已在线的角色登录,需要先把已登录的客户端踢下线。
如何解决:需要一个记录agent在线状态的服务agentmgr。
2、完整登录流程
下图展现了登录过程中最复杂的一种情形,即假设客户端B已在线,客户端A要在另一节点登录同一账号。
- 虚线内的服务位于同个节点;
- 不同虚线方框的服务可能配置于不同节点;
- gateway及其对应的login和agent一定位于同一节点上;
- agentmgr可位于任意节点上。
阶段 | 说明 |
① |
客户端A连接服务端某个节点的某个gateway (为实现负载均衡,客户端知道所有gateway的地址,并随机选择一个) |
② |
虽然能连接上,但服务端并不知道客户端A要登录哪个角色。客户端A发送消息,消息包含账号和密码,gateway收到后,随机选择节点内某个login服务,并将消息转发给它 (login服务是无状态的服务,专门用于处理登录校验,一个节点可以开启多个login服务,以分散负载) |
③ |
账号,密码通过校验后,login服务会向agentmgr发起登录请求 agentmgr会记录所有在线玩家的状态(包括登录中、游戏中、登出中),通过向agentmgr发起请求 agentmgr可以判断账号是否已登录。如果未登录,直接进入阶段⑥,否则先将已登录的客户端踢下线 agentmgr是个“权威”的服务,角色能不能上线,能不能下线都由它裁决 |
④ | agentmgr要求原客户端对应的agent下线(发起kick和exit请求),原agent会保存角色数据,然后退出服务。 |
⑤ | agentmgr通知原客户端对应的gateway,让它告诉客户端B“你已被踢下线”。然后设置gateway的状态,取消客户端B与角色101的关联 |
⑥ |
agentmgr向nodemgr请求创建agent服务 nodemgr即节点管理器,它可以提供创建服务、节点监控等功能 |
⑦ | 创建客户端对应的agent,新agent读取角色数据 |
⑧ | agent创建完毕,agentmgr会记录角色处于“已登录”状态,再通知gateway,让它把新客户端和新agent关联起来 |
⑨ | 进入游戏阶段,客户端发送的消息被转发到新agent上 |
3、掉线登出流程
当客户端掉线时,登出流程如下图所示:
阶段 | 说明 |
① | 客户端A掉线,gateway要取消客户端与agent的关联 |
② | gateway向agentmgr发起下线请求,所有上线下线的请求都必须由agentmgr仲裁 |
③ | 如果仲裁通过,agentmgr要求代理服务agent下线(发起kic和exit请求),agent会保存角色数据,然后退出服务 |
4、总结
登录登出过程涉及的步骤较多,越多就越复杂,也就越容易出错。
问题:
假设客户端B已在线的情形,但如果在客户端B登录的过程中(比如角色数据尚未全部加载),客户端A请求登录,又该如何处理?会不会造成数据紊乱?
解决:
这些情况颇为复杂,我们的解决办法是。所有上线下线的请求都要经过agentmgr,由它裁决,只有“已在线”状态的客户端方可被顶替下线,如果处于“登录中”或“登出中”,agentmgr会告诉新登录的客户端“其他玩家正在尝试登录该账号,请稍后再试”。