分区分服与大规模跨服功能


© 内容版权所有,转载或复制需附源站地址 www.tanjp.com 谢谢合作。

变更记录

2020-04-24, tanjp, 编写第一版 整体的架构设想。

名词说明

分区分服,是指游戏服务端的部署上划分不同的游戏入口,直接的感受就是玩家需要选择一个服务器进行登录后再创建角色进行游戏。具体的划分按运营的需求,可按地区划分不同的服,如A区[1服~10服],B区[11服~20服],等等。


大规模跨服,是指不同地区服务器上的玩家可以一起玩耍,如A区1服玩家A与B区20服玩家,可以加好友,加入同一个公会,可以聊天,就一个问题讨论,可以组队去PVE,或者去跟另一组进行PVP,等等。

一、总体架构设计图


二、数据存储

2.1 数据存储分类

角色数据,就是一个玩家自身的属性变化,如背包,经验等级,等等。(一般采用整块回写)社交数据,就是把多个玩家的数据通过某种形式的整合,如公会,好友,聊天,组队,等等。(实时回写或定时回写)状态数据,不被用户感知,但是在程序实现过程中的逻辑状态,如在线状态,XXX标记,缓存状态,能否被删除,等等。(一般存在于内存,可根据需要是否落地,或者缓冲在Redis,可全局访问)环境数据,在架构全局中起到分配或者负载均衡作用,又或者启动了哪些进程?数据与进程之间的关系如何?(可以是配置信息,动态部署数据)

NOTE: 数据落地保证幂等性,避免重复写入导致数据错误。

2.2 存储方案

1) 角色数据存储
,采用 MongoDB 存储。

每个角色服对应一个数据库,角色数据一旦创建就永远存在于该数据库,合服也无需进行数据迁移。一般来说,一个服一般是导入2~3万左右角色数量,不同的功能划分存储在不同的 document 即可。RoleDBS 为角色存储服务,专职负责数据库的读写,根据读写的压力,可适当调整单DBS负载数 S。

具体结构如下图:

2) 社交数据存储,采用 MongoDB 存储。

社交数据是所有服共用的一份数据,而且数据量根据不同的功能有所不同,甚至差异很大。譬如公会,假设全服公会数量最多有10万个,每个公会里有许多条角色信息,并且每个工会都有一个公会玩法数据(假设较大10M),如此一来最大可能公会数据就有1000G数据,就需要进行数据划分。假设划分为100个数据库,每个最大为10G,当然还有一个所有公会概要信息数据库,最多也就是10万条数据。

具体结构如下图:

3)
状态数据存储,采用多个 Redis 按一致性HASH的方式存储。

这里的状态数据,可能有些必须要存储于内存。有些需要落地到硬盘,以便服务器重启后数据依旧可用。譬如,玩家的在线状态,只需要存在内存,一旦玩家下线了就可以删除或者修改为下线。而玩家的简要信息可能会被各个系统访问,如各种等级,头像框,战斗力等等,而且服务器重启也要能访问。因此,存储于 Redis 的数据分为两类,一类状态数据需要落地,另一类状态数据只需存在于内存

另外,考虑到用户量可能会相当大,假如百万用户在线(虽然只有极少数游戏或者公司能达到),日活估计得千万,也就是说状态缓存得千万用户级别。所以需要把状态划分多个存储于 Redis 上,假如是千万缓存用户量,每个用户缓存的数据量为 10KB,千万用户就是要 100GB 的缓存 ,每个 Redis 实例不超过 10GB的话,就需要 10个 Redis 实例。所以需要按用户ID 映射到不同的 Redis 实例上,实现均衡分布。

具体结构如下图:

4)
环境数据存储,采用 Zookeeper 集群存储。

多进程分布式的架构,往往会有几十个甚至几百上千个进程在同时运行而组成整套系统。所以,必须要统一的配置管理,由订阅发布机制来实现所有进程的配置更新。还有当几百个进程同时在协作时,很难避免有个别进程由于各种原因导致不可用,这时就需要用新的服务节点替换故障的节点,这就涉及服务治理和服务发现。这一块,还有挺多学问,还需日后继续深入深究。


三、玩家交互

3.1 与玩家交互的四种方式

账号登录验证,选服推荐,白名单机制,入口管理,等等。主要采用 Web HTTP的方式进行交互,主要保障高并发和高可用,由于这些功能都比较简单,通过 Nginx 多节点负载均衡的方式,就能达到很好的效果。账号登录成功并选服后,客户端直连角色逻辑服,然后就是开始频繁的交互,进入正常的游戏逻辑。当玩家参与了一个跨服玩法时,需要与其他区服的玩家进行一场强交互的玩法时,就需要把所有相关玩家都连接到另外一个玩法房间,此时客户端与服务端之间保持量两条网络连接,分别负责不同的功能职责。游戏内往往有一些内嵌的网页小活动,这种交互也是通过 HTTP 请求与 Nginx 交互,并转发到服务端内部。

3.2 跨服玩法的特点分类

多人在较为短的时间强交互(频繁的操作和响应),这种采用跨服房间的方式实现,多个客户端同时连到该房间,进行强交互的玩法,并且在最后结算的时候才发放相关的奖励。多人在很长的时间里进行弱交互(操作和响应不频繁),这种采用类似公会系统的实现方式,在服务端内部通过RPC调用内部服务来完成功能玩法的实现,最为关键就是处理好数据一致性问题。介于强交互与弱交互之间的玩法,得根据需求的复杂性来决定到底如何实现。

四、进程职责

DBS进程(存储服)负责最大限度发掘数据库存取性能,除了Nginx,所有其他进程读写数据都是通过DBS来完成。DBS是独立无状态的集群,只为各个进程提供准确读写数据库的服务。route进程(路由服)只作为转发进程,只负责高性能的数据转发服务。route是无状态集群,每个进程都连上所有路由,任何一个路由都能转发数据,但需在业务层按策略实现负载均衡。role进程(
角色服)为指定区服的客户端提供服务,同时连接到route进程,调用其他社交系统的接口。可按运营策略进行动态扩展。room进程(房间服)为不同区服的客户端提供一个一起玩耍的跨服玩法服务,同时连接到route进程调用其他社交系统的接口。可根据具体玩法的负载情况,实现动态分配和扩展。social类进程(社交服),连接到route进程,为各服所有玩家提供社交系统接口,根据系统负载情况,可预先设定进程数量以满足需求,也可实现服务治理与服务发现。主要存储数据库采用 MongoDB, 采用 Redis 存储全局状态管理,采用 Zookeeper 来实现配置管理和服务发现。充值流水等核心数据采用 Mysql 存储。实时的错误信息或关键信息的上报和监控,也采用 Mysql 来存储。非核心的流水日志或运行日志,用 filebeat 和 logstash 进行采集,并导入 Elasticsearch,并实现关键信息的监控和报警功能。

五、运维监控

运行日志监控关键字 ERROR,并作告警处理。流水日志按策划需求,监控异常数据的发生,并告警。所有进程的CPU,内存,通讯延时监控。逻辑功能监控,在线人数,缓存人数,公会数量,组队数量,地图数量,等等。RPC成功率,各个Actor占用内存,关键函数执行时间。运维操作,自动部署,启动,关闭,重启,更新,维护状态,等等。

© 内容版权所有,转载或复制需附源站地址 www.tanjp.com 谢谢合作。