架构实战营 模块 3 作业
游戏业务消息队列中间件详细架构设计文档
前言
本文是游戏业务消息队列中间件详细架构设计文档,用于指导消息队列后续的开发、测试和运维。
词汇表
Reactor:网络编程模式
Netty:开源的网络编程框架
Shard:数据分片,将数据拆分的一种技术
Zookeeper:分布式服务协调中间件,用于主备切换
1. 业务背景
游戏业务发展很快,系统也越来越复杂,目前系统间的调用都是同步调用,由此带来几个明显的系统问题:
性能问题:当有新的游戏版本发布时,运营管理子系统需依次通知“论坛”、“包管理子系统”、“app”和“web”等子系统,性能较低(如图一);
耦合问题:各个系统之间是高内聚低耦合,比如游戏充值业务,充值子系统需要调用 vip 子系统,vip 子系统调用等级子系统,子系统继续调用客服子系统,客户子系统再通知商品子系统(如图二);
效率问题:每个子系统提供的接口参数和实现都有一定细微的差别,导致每次都需要重新设计接口和联调接口,开发团队和测试团队花费了许多重复工作量。
基于以上背景,我们需要引入消息队列进行系统解耦,将目前的同步调用改成异步通知,提高耦合度。
图一:游戏版本发布系统边界黑盒图
图二:充值服务系统边界黑盒图
2. 约束和限制
1)必须在 2021.07.30 号完成
2)成本不能超过 500 万
3)数据库采用 mysql
3. 总体架构
消息队列系统主要分为客户端 sdk 和服务端两部分,业务系统集成客户端 sdk,通过客户端 sdk 对消息队列服务端进行读写操作完成业务逻辑,从而有效解耦了各个业务系统,如图三。
图三:消息队列系统边界白盒图
消息队列服务端有包含服务程序 httpServer、存储 mysql、主备切换 zookepper 三部分,如图四。其中 httpServer 采用分组部署的方式实现高可用,每组分为主备两台机器,通过 zookeeper 实现主备切换,每组 httpServer 采用一组主备的 msyql 进行存储确保数据高可用,mysql 主备之间通过 binlog 方式实现数据同步。
图四:消息队列框架图
3.1 架构分析
3.1.1 高可用
对于游戏版本发布和登记子系统来说,都是高优先级业务,若出现不可用将导致用户流失从而损失收入。
3.1.2 高性能
因为消息新版本发布、VIP 充值业务不是很频繁,所以不需要考虑高性能。
3.1.3 可扩展
当前消息队列的功能基本明确,无需扩展。
3.2 总体架构
消息队列系统整体架构图如图五,主要内容说明如下:
1)消息队列系统主要由客户端 sdk 和服务端 httpServer 组成,客户端 sdk 和 httpServer 基于 java 语言开发;
2)使用 netty 自定义消息格式,并且支持 http 接口;
3)消息存储采用 mysql;
4)采用数据分散集群的架构,及集群的服务器进行分组,每个分组分为主备两台服务器,每个分组存储一部分的消息数据,根据消息队列的 id 的 hash 进行分组,每个消息队列存储在其中的一个分组上;
5)每个分组包含一台主 mysql 和一台备 mysql,分组内主备数据复制,分组间数据不同步;
6)正常情况下,分组内的主服务器对外提供消息写入和消息读取服务,备服务器不对外提供服务;
7)主服务器宕机的情况下,备服务器对外提供消息读取的服务,获取到的客户端写入请求将被拒绝;
8)客户端 sdk 采用轮询的策略写入和读取消息;
9)每组主备服务器之间基于 zookeeper 实现主备切换。
图五:消息队列整体架构图
4. 详细设计
消息队列系统角色主要有生产者和消费者,核心功能主要为消息发送、消息消费、消息存储以及服务主备切换三个模块。
4.1 核心功能
4.1.1 消息发送流程
(1)消息队列系统设计两个角色:生产者和消费者,每个角色都有唯一的名称;
(2)消息队列系统提供 sdk 供各业务系统调用,sdk 从配置中读取所有消息队列系统的服务器信息,sdk 采取轮询算法发起消息写入请求到主服务器;
(3)如果某个主服务器无响应或者返回错误,sdk 将发起请求发送到下一台主服务器,相当于在客户端实现了分片的功能;
4.1.2 消息消费流程
(1)消息队列系统提供 sdk 供各业务系统调用,sdk 从配置中读取所有消息队列系统的服务器消息,轮流向所有服务器发起消息读取请求。
(2)消息队列服务器需要记录每个消费者的消费状态,即当前消费者已经读取到了哪条消息,当收到消息读取请求时,返回下一条未被读取的消息给消费者。
4.1.3 服务器主从切换
(1)同一组的主从服务器配置相同的 group 名称,在 zookeeper 建立对应的 persisent 节点
(2)主从服务器启动后,在 zookeeper 对应的 group 节点下建立 ephemeral 节点,名称分别为 master 和 slave;
(3)从服务器 watch 主服务器的 master 节点状态,当 master 节点超时被删除后,从服务器接管读消息,收到客户端 sdk 的读请求消息后返回消息,收到客户端 sdk 的写强求直接拒绝。
4.2 关键设计
4.2.1 消息发送可靠性
1)业务服务嵌入消息队列系统提供的 sdk,sdk 支持轮询发送消息,当某个分组的主服
务器无法发送消息时,sdk 挑选下一个分组主服务器重发消息,依次尝试所有主服务器直到发送成功;
2)如果全部主服务器都无法发送,sdk 可以通过配置消息策略来处理消息,比如消息
丢弃,消息存入客户端缓存里,消息存入持久化数据库里,比如 redis 或者 mysql。
4.2.2 消息存储可靠性
1)消息存储在 mysql 中,每个分组有一主一备两台 mysql 服务器,mysql 服务器之间复制消息以保证消息存储高可用;
2)对 mysql 主从复制延迟进行监控,当复制延迟超过 30s 的时候产生告警并进行运维手工干预处理;
3)当 mysql 主从复制发生延迟且在 30s 内,恰好此时 mysql 主服务器宕机导致数据无法恢复,这种情况可接受。
4.2.3 消息及消息状态存储
1)每个消息队列对应一个 mysql 表,消息队列名就是表名,表设计结构设计如下:
2)每个消息队列消费情况对应一个 mysql 表,表名为“消息队列名_consumeinfo”,
表设计结果如下:
3)消息按月进行清理,以 collectTime 为判断,每月清理一个月以前的消息。
4.3 设计规范
1)消息队列服务器采用 springboot + netty 开发;
2)消息队列 sdk 采用 java 开发;
3)Mysql 使用 innodb 存储引擎;
4)Zookeeper 采用三节点集群部署方式;
5)tcp 包的结构设计为:crc(int32 消息完整性校验)+magincByte(int8 消息版本性兼容标识,默认为 0)+attributes(int8 消息的元数据信息,最后低两位标识消息是否压缩存储以及压缩方式)+value(bytes,消息具体内容)。
5. 质量设计
5.1 消息队列管理后台
消息队列管理后台包含权限管理、配置管理、监控和维护四个模块,如图六。
权限管理是针对各个业务系统对消息队列表的读写权限管理;配置管理是维护消息队列服务器信息、以及每组消息队列服务器维护的消息队列表信息;监控主要是通过 prometheus 监控 sdk、消息队列服务器、mysql、zookeeper 等组件运行情况;维护是指通过发送命令的方式管理消息队列服务器。
图六:消息队列管理系统模块图
5.2 成本
中间件研发团队投入较低,实现成本低;
测试需要投入一定的人力,对消息队列服务器、mysql 高可用进行测试;
运维团队来说运维成本会较高,需要的硬件较多,需要 8-12 台服务器。
6. 演进规划
6.1 消息队列一期
一期完成客户端 sdk、消息队列服务端(单点)、消息队列管理系统(配置管理、权限管理)开发。
6.2 消息队列二期
二期完成消息队列服务器高可用、消息队列管理系统(监控、维护)开发。
评论