前言

公会是游戏功能中玩家数据交互最为频繁的一个功能,如何让多个玩家操作同一份数据有序而不出错是个很值得非常重要的问题。NodeJS服务器由于无阻塞、单线程、异步、集群的特点使得此功能难点又增加N个百分点,本文分享自己单进程公会服的设计经验。

核心问题

  • 其它服务器和公会服交互
  • 公会服如何承担访问压力
  • 公会玩家基本信息同步问题
  • 同一公会中会长A请求把会员C设为副会长和副会长B把会员C设为大队长,操作如何保证会员C最终职位为副会长,副会长B操作被否决。
  • 公会A和公会B同时批准玩家C入会,如何保障先到先得,玩家C只在一个公会。

进程间通信

  • 传统方式采用RPC方式,比如客户端GameServer访问需要修改公会数据
  • 通过Redis发布订阅,比如一些广播请求

服务器压力

  • 公会服除内存存放数据外另外在Redis缓存维护一份供其它进程读取。
  • 客户端不和公会服连接,所有操作都是通过GameServer转发
  • 客户端对公会的查询操作,通过GameServer访问Redis即可
  • GameServer承担客户端消息的基本容错,只有存在修改数据时才访问公会服
  • 公会成员、公会申请、公会操作日志等数据量较大的UI上做为子标签页打开访问

玩家信息同步问题

  • 创建公会成员数据对象,分别有姓名、等级、在线时间、公会ID、职位、入会时间、公会贡献等属性
  • 没有申请、创建、加入公会的没有此对象,
  • 创建公会成员不和公会对象直接绑定,公会只是公会成员的一个属性
  • 玩家上下线同步此对象数据,如有特殊需求,可做策略比如每3小时同步一次数据

数据锁问题

  • 每个公会对象和每个公会成员对象增加一个属性,标识是否为不可写状态
  • 每个公会对象和每个公会成员对象增加一个消息队列,用来存放等待的请求
  • 公会对象、公会成员对象为不可写状态时,数据访问需要等待直到状态解除
  • 等待状态保护机制一定时间内不返回,请求当失败返回
  • 修改公会加公会锁,修改玩家加玩家锁,同时修改时,需要同时加,访问也要等待所有状态解除

瓶颈

由于是采用单进程,虽然有策略分担了大部分压力,但终究对于大部分玩家都在操作工作时会出问题。所以,对公会的功能开发需要仔细考虑,比如公会功能放到一定等级才开放,公会部分操作设置冷却时间,部分功能可以考虑利用redis在其它进程实现。而这进一步,则需要的更加缜密的思维,以及天才般的想法。

关于公会集群的想法

由于公会都有固定的ID,我们可以通过Hash算法使每次对公会的操作准确命中对应的进程。当然,肯定还有其它坑要踩,比如两个公会操作同一个玩家数据时,怎么对应。知识范围有限,还未有有效的方法。

结束语

又到了说再见的时候了,此方案果然经不起仔细的推敲,知识掌握程度限制了对自己的思维能力。技术能力又使自己不能干脆的做出用C++或者GO语言实在公会服的设计决定。 总之,思路依然幼稚,贻笑大方了。