思考(六十一):MMO 微服务架构思路推演

MMO 微服务架构思路推演

传统的 MMO 架构有很多局限性,主要有以下几点:

  1. 承载量有限
  2. 基于这种架构上, BigWord 无缝世界实现非常复杂
  3. 无法融入微服务这种更先进架构中

因此,本人提出一种 MMO 微服务架构,并以此架构为基础,借 MMO 典型玩法,来推演这种架构是否符合要求

并解决上述 3 个问题

架构图

                                                              +---------------+
                                                    +-------->+    Base N     +----------------------+
                                                    |         +-------+-------+                      |
                                                    |                 ^                              |
                                                    |                 |                              v
+---------------+             +---------------+     |         +-------+-------+               +------+--------+
|   Client N    +------------>+   Gateway N   +-------------->+    Game N     +-------------->+     Redis     |
+---------------+             +---------------+     |         +-------+-------+               +------+--------+
                                                    |                 |                              ^
                                                    |                 |                              |
                                                    |                 v                              |
                                                    |         +-------+-------+                      |
                                                    +-------->+     AOI N     +----------------------+
                                                              +---------------+

各服务主要职能:

服务名 职能 典型玩法 特点
Base 玩家个人玩法 角色属性系统
背包系统
装备系统
无状态,仅逻辑
使用协程方式,同步操作 Redis 存档数据
AOI 场景 AOI 管理 AOI 系统 无状态,仅逻辑
负责某个世界场景的分片 AOI
Game 地图场景中玩法 打怪/PK
拾取/丢弃
装备/卸下
无状态,仅逻辑
使用协程方式,同步访问 Base、 AOI
使用协程方式,同步操作 Redis 存档数据
有短暂的战斗串行化协程(后续介绍)
Gateway 转发消息 转发个人玩法消息
转发 AOI 消息
内存中维护客户端网络会话
Redis 各玩法存档数据
游戏对象 AOI 数据
ROLEID - GATEWAYID
ROLEID - BATTLE_GAMEID
- -

服务定位:

  • Base 简单微服务,提供基础玩法服务接口
  • AOI 简单微服务,只提供 AOI 相关服务接口
  • Game 场景玩法微服务,Base 、 AOI 作为上游服务,供其使用;并向玩家提供相关场景中玩法服务

MMO 典型玩法一: 角色属性系统/背包系统/装备系统

Base 服上实现

思路同 PHP 编程,抽象设计好系统接口。每个接口实现,直接协程同步操作 Redis

同时 Base 可以提供 RPC 接口,供 Game 调用

Base 不需要 ROLEID - GATEWAYID/GAMEID 信息,哪个 Gateway/Game 发来的请求,原路返回即可

MMO 典型玩法二: AOI 系统

AOI 服上实现

AOI 系统,功能包括:

  • 游戏对象场景中创建、移动、销毁
  • 获取某块区域内游戏对象信息
  • 管理游戏对象视野。进入视野、离开视野、在视野中移动
  • 场景中射线检测、碰撞检测

传统 MMO 架构中,通常这些功能都是会在称为Cell服务上

Cell服主要有个问题: AOI 系统、战斗系统是关联在一起的,并与 Cell服也捆绑在一起

角色战斗数据 、 AOI 数据,在 2 个相邻Cell服边缘需要特殊处理:

  • 比如角色战斗数据需要跨 Cell 同步
  • 比如无缝世界还需要主从切换等

因此,需要把战斗数据/战斗逻辑与AOI数据/AOI逻辑分开

AOI 服只处理AOI数据/AOI逻辑;AOI数据不需要跨服同步,只做些冗余即可

主要实现原理如下:

  • 将整个世界分片,每片对应一个 AOI 服(或者双备下,开2个),以下简称分片 AOI 服
  • 分片 AOI 服 Redis 中维护各自 X 、 Y 、Z 3 个轴的 zset 数据(以及AOI相关的玩家数据如 roleid - hmap(speed/face/state) )
  • 分片 AOI 服冗余周围9格分片的部分 X Y Z 信息
  • AOI 算法使用十字链表法

具体实现逻辑要点:

功能 操作
游戏对象场景中创建、移动、销毁 分片 AOI 服直接对 Redis X 、 Y 、Z 3 个轴的 zset 数据做更新
获取某块区域内游戏对象信息 十字链表法从 Redis 中获取某块区域内游戏对象信息
管理游戏对象视野。进入视野、离开视野、在视野中移动 Redis 保存角色ID-视野信息快照
创建、移动、销毁请求时,获取某块区域内游戏对象信息
计算事件
保存新角色ID-视野信息快照
场景中射线检测、碰撞检测 获取某块区域内游戏对象信息;再做射线检测、碰撞检测

性能分析,主要瓶颈如下:

  • 某个分片的上 Redis 上有各自的 3 个 zset , 对这 3 个 zset 的存取是一个分片 AOI 服的 TPS 上限
  • redis 对同一个 KEY 的 TPS 范围在: 5w-50w/TPS,一般 10w+/TPS
  • 分片 AOI 服 CPU 消耗点是:管理游戏对象视野。进入视野、离开视野、在视野中移动与场景中射线检测、碰撞检测。5w-50w/TPS 下 CPU 未到达 100% ,不考虑双备 1 个进程即可;否则按 CPU 满的情况,多开
关于 AOI 服的更新问题

文中把 AOI 服定义为完全无状态,因此移动中的玩家,状态更新,只能依赖于客户端定时发送移动事件来驱动。

这样做好处是 AOI 完全无状态,最简单。

如果希望 AOI 服务自己主动刷新移动中的玩家,则无法做到完全无状态,必须内存中维护玩家列表,以及位置、速度信息;并做定时 Update

另外考虑到 AOI 服务每秒定时更新的次数是有限的,通常 20 - 30 帧左右,那么也可以考虑直接 Redis 中维护一个 hmap,保存玩家列表,以及位置、速度信息

这样依然可以让 AOI 服,完全无状态

MMO 典型玩法三: 打怪/PK、拾取/丢弃、装备/卸下

Game 服上实现

有了上游服务 Base、 AOI 服,打怪/PK、拾取/丢弃、装备/卸下 就是些逻辑组合了

注意:Game 上是无场景概念的,只有各种逻辑;即 某个 Game 服不会只处理某场景上的逻辑,除非刻意为之

一、 打怪/PK

打怪/PK 要点:

  • Game 是无状态的,每次战斗逻辑,都会去 Redis 中存取相关数据,类似 PHP 做法
  • 从玩家进入战斗状态,到脱离战斗状态,因为会涉及到多个玩家或怪物。因此需要申请ID号,并交给某个 Game 处理
  • 玩家进入战斗状态时,先 Redis 中获取ID号(无创建之),然后他的战斗消息都会投递给同个 Game
  • 玩家战斗中,主攻攻击/被击游戏对象玩家等都会关联到同个ID号上,直到脱离战斗状态为止
  • 本质上就是一个虚房间的概念
二、 拾取/丢弃
  • Game RPC AOI 请求创建或销毁游戏对象
  • Game RPC Base 背包系统
三、装备/卸下
  • Base 装备/卸下
  • Redis 中战斗属性数据更新 (看代码实现,假设战斗相关功能都在 game 上,则查看战斗ID号,如果有投递给相应 Game)

动态分片

由于分片只处理 AOI 数据,实现动态分片的难度也简单了。

把世界画成完全二叉树的正方形2叉分割图。

可以把问题简化为完全二叉树的节点分割与合并的算法基础上,维护下 AOI 数据

细节:

  • 动态分片与物理地图资源分片,需要协调好。 2 者不一定要一致
  • 物理地图资源分片必须必动态分片要大
发布了129 篇原创文章 · 获赞 73 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/u013272009/article/details/103992949