写点什么

消息队列架构设计文档

发布于: 2021 年 05 月 07 日

前言

本文是游戏业务线消息队列中间件详细架构设计文档,用于指导消息队列后续的开发、测试和运维。

词汇表

Reactor: 网络编程模式

Netty: 开源的网络编程框架

ISO 27701: 隐私信息管理体系认证

1. 业务背景

游戏业务发展很快,系统也越来越多,系统间协作的效率很低,例如:

  • 效率问题:玩家进行充值,充值完成后充值子系统通知 VIP 子系统; VIP 子系统判断玩家等级,达到 VIP 后,等级子系统要通知福利子系统进行奖品发放,要通知客服子系统安排专属服务人员,要通知商品子系统进行商品打折处理……等级子系统的开发人员也是不胜其烦。

  • 耦合问题:各个子系统之间的相互调用,增大了系统的耦合性。

基于以上背景,我们亟需引入消息队列进行系统解耦,将目前的同步调用改为异步通知。而综合分析各开源消息队列以及阿里内部的消息队列,最终决定采用自研消息队列的方案。

以下系统边界黑盒图来描述系统与外界的边界和交互关系:

2. 约束和限制

  • 投资方的成本要求:不超过 100 万

  • 监管方的监管要求:符合 ISO 27701 标准

  • 技术选型的硬性要求:使用 MySQL 作为数据存储

  • 项目时间要求:不得超过 3 个月

  • 质量要求:符合 ISO 27701 标准

3. 总体架构

3.1 架构分析

3.1.1 可维护性

  • 方案可以融入到现有的运维体系中,而且使用 MySQL 存储数据,可靠性有保证,运维团 队也有丰富的 MySQL 运维经验

  • 对业务团队 来说,只要保证消息队列系统稳定和可靠即可

3.1.2 业务场景

可以为业务场景定制开发各种特性,例如:

  • 权限控制

  • 费速度预警

等等。

3.1.3 性能

部分研发人员对于这个方案的性能持怀疑态度,毕竟使用 MySQL 来存储消息数据,性能肯定不如使用文件系统。但综合分析性能不成问题:

  • 每个消息队列对应一个表

  • 消息表最多存储 30 天内的消息,过期的自动清除

  • 消息队列还通过分片(sharding)来减小 MySQL 服务器的压力

  • MySQL 的 TPS 达到 1000 没问题

3.2 总体架构

系统边界白盒图描述系统内的角色与外界的交互(Rank + Role + 外部 Relation):

系统架构图来描述内部的 Role + 内部 Relation:

  • 客户端 Role 设计

  • 客户端采用 Java 语言开发,基于 Netty 实现与服务端交互

  • 服务器 Role 设计

  • 服务器基于 Netty 开发,采用 Reactor 网络模型

  • 两台服务器组成一个 sharding,整个系统可以多个 sharding,每个 sharding 包含一主一从两台服务器(可以对比 MongoDB shard)

  • 主服务器提供消息读写操作,从服务器只提供消息读取操作

  • 服务器基于 ZooKeeper 进行主从切换

  • 客户端和服务器的 Relation 设计

  • 客户端与服务端采用 TCP 连接,采用 Json 传递数据

  • 为了兼容非 Java 系统,服务端同时提供 HTTP 接口

  • MySQL 的 Role 和 Relation 设计

  • 采用 MySQL 主从同步

  • 每个消息队列对应一个表

  • 消息表最多存储 30 天内的消息,过期的自动清除

  • 直接用 MySQL 的主从复制来实现数据复制

4. 详细设计

4.1 核心功能

4.1.1 消息发送流程


  • 消息队列系统涉及两个角色:生产者和消费者,每个角色都有唯一的名称

  • 消息队列系统提供 SDK 供各业务系统调用,SDK 从配置中读取所有消息队列系统的服务器信息,SDK 采取轮询算法发起消息写入请求给 主服务器

  • 如果某个主服务器无响应或者返回错误,SDK 将发起请求发送到下一台主服务,相当于在客户端实现了分片的功能

4.1.2 消息消费流程

  • 消息队列系统涉及两个角色:生产者和消费者,每个角色都有唯一的名称

  • 消息队列系统提供 SDK 供各业务系统调用,SDK 从配置中读取所有消息队列系统的服务器信息,轮流向所有服务器发起消息读取请求

  • 消息队列服务器需要记录每个消费者的消费状态,即当前消费者已经读取到了哪条消息,当收到消息读取请求时,返回下一条未被读 取的消息给消费者

  • 默认情况下主服务器提供读写服务,当主服务器挂掉后,从服务器提供读消息服务

4.2 关键设计

  • 服务器主从切换

  • 同一组的主从服务器配置相同的 group 名称,在 ZooKeeper 建立对应的 PERSISENT 节点

  • 主从服务器启动后,在 ZooKeeper 对应的 group 节点下建立 EPHEMERAL 节点,名称分为为 master 和 slave

  • 从服务器 watch 主服务器的 master 节点状态,当 master 节点超时被删除后,从服务器接管读消息,收到客户端 SDK 的读消息请求后返回 消息,收到客户端 SDK 的写请求直接拒绝

4.3 设计规范

  • 消息队列服务器使用 Spring Boot + Netty 开发

  • MySQL 使用 Innodb 存储引擎

  • TCP 包的结构设计采用 JSON 明文格式

  • 需要支持 HTTP 接口

5. 质量设计

5.1 可测试性

  • 可在消息队列管理系统:

  • 查看消息、队列和分片

  • 消费消息

  • 查看消息

  • 修改消息状态

  • 主备倒换

  • 主备切换

  • 增减分片

5.2 可维护性

  • 可在消息队列管理系统:

  • 查看消息、队列和分片

  • 修改消息状态

  • 消费消息

  • 关闭分片

  • 增减分片

  • 关闭队列

5.3 可观测性

  • 可在消息队列管理系统:

  • 查看消息、队列和分片

5.4 成本

  • 第一版采用两个分片

  • 如果效率不足,增加分片

6. 演进规划

6.1 消息队列一期

  • 本文内容

  • 如果 deadline 无法保证

  • 简化权限管理

  • 简化监控

  • 简化维护

6.2 消息队列二期

  • 完善消息队列管理系统

  • 优化消息队列管理系统

6.3 消息队列三期

  • 尝试用 HBase 替换 MySQL

  • 制作内部测试版

6.4 消息队列四期

  • 如果用 HBase 替换 MySQL 效果明显

  • 制作最终生成版

用户头像

还未添加个人签名 2018.08.01 加入

还未添加个人简介

评论

发布
暂无评论
消息队列架构设计文档