写点什么

架构训练营模块 3 作业 - 消息队列架构设计

用户头像
关注
发布于: 2021 年 05 月 09 日

前言


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


词汇表

1. 业务背景


随着游戏业务的不断发展,业务上拆分的子系统越来越多,目前系统间的调用都是同步调用,由此带来几个明显的系统问题:

  • 性能问题:当玩家进行充值,充值完成后充值子系统需要同步调用 VIP 子系统进行福利、奖品发放。充值完成后充值子系统需要调用订单子系统,通知其修改充值单状态,充值完成后充值子系统需要同步调用通知推送子系统给用户推送一条充值成功的消息。一个充值业务充值子系统需要同步调用 N 个其它子系统,性能很低。

  • 耦合问题:当新增一个子系统时,例如如果要增加“清结算子系统”,那么充值子系统需要同步调用清结算系统有充值单支付成功,以便其后续对款项进行清分。

  • 效率问题:每个子系统提供的接口参数和实现都有一些细微的差别,导致每次都需要重新设计接口和联调接口,开发团队和测试团队花费了许多重复工作量。

基于以上背景,我们需要引入消息队列进行系统解耦,将目前的同步调用改为异步通知。

2. 约束和限制

1、中间件团队规模不大,大约 6 人左右。

2、 中间件团队熟悉 Java 语言,但有一个同事 C/C++很牛。

3、 开发平台是 Linux,数据库是 MySQL。

4.、目前整个业务系统是单机房部署,没有双机房。

5、能够方便运维,能够用较低成本接入现有运维系统。

6、成本不能太高、预算 500W 左右。

7、开发周期不能太长、预计三个月时间。

3. 总体架构

自研集群+MySQL 存储:Java 语言编写消息队列服务器,消息存储采用 MySQL,SDK 轮询服务器进行消息写入,MySQL 双机保证消息尽量不丢失,使用 Netty 自定义消息格式,并且支持 HTTP 接口

3.1 架构分析


3.1.1 高可用

对于充值子系统来说,如果消息丢了,导致用户被扣款了,充值单状态还是待支付,用户会立刻咨询客服,如果游戏用户基数比较大,一段时间内充值比较频繁、消息短暂的不可用,对业务来说都是一个灾难,清结算子系统收不到充值单数据,也不会对充值单进行清分,这会导致资损,对于 VIP 子系统福利、奖品的发放关系倒不是很大,综合来看,消息队列需要高可用性,包括消息写入、消息存储、消息读取都需要保证高可用性。

3.2 总体架构



1)采用数据分散集群的架构,集群中的服务器进行分组,每个分组存储一部分消息数据。

2)每个分组包含一台主 MySQL 和一台备 MySQL,分组内主备数据复制,分组间数据不同步。

3)正常情况下,分组内的主服务器对外提供消息写入和消息读取服务,备服务器不对外提供服务;

4)主服务器宕机的情况下,备服务器对外提供消息读取的服务。

5)客户端采取轮询的策略写入和读取消息。

4. 详细设计


【客户端设计】

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

【MySQL 数据库设计】

1. 采用 MySQL 主从同步。

2. 消息表设计成一个大表,用 msgType 区分消息类型。

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

4. 直接用 MySQL 的主从复制来实现数据复制。

【客户端和服务器的设计】

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

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

【服务器设计】

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

2. 两台服务器组成一个 sharding,整个系统可以多个 sharding,每个

sharding 包含一主一从两台服务器。

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

4. 服务器基于 ZooKeeper 进行主从切换。



4.1 核心功能


4.1.1 消息发送流程

业务系统集成消息系统 SDK,SDK 中有定时任务自动从配置中读取消息队列系统的服务器信息,并更新自己的本地服务器信息列表。

发送消息时,SDK 查询本地服务器列表中,随机获取一个消息服务器地址,并给消息服务器发送消息,如果成功,流程结束;否则,再次随机获取一个消息服务器地址,执行上述流程。

4.1.2 消息消费流程

业务系统集成消息系统 SDK,SDK 从配置中读取所有消息队列系统的服务器信息,不断轮询着向某一个消息服务器发起消息读取请求,消息队列服务器需要记录每个消费者的消费状态,即当前消费者已经读取到了哪条消息,当收到消息读取请求时,返回下一条未被读取的消息给消费者。 当消费者完成消息的消费时,需要给消息队列服务器一个响应,以便消息服务器能够记录当前消息的消费状态。

4.2 关键设计


1)消息发送可靠性

业务服务器中嵌入消息队列系统提供的 SDK,SDK 支持轮询发送消息,当某个分组的主服务器无法发送消息时,SDK 挑选下一个分组主服务器重发消息,依次尝试所有主服务器直到发送成功;如果全部主服务器都无法发送,SDK 可以缓存消息,也可以直接丢弃消息,具体策略可以在启动 SDK 的时候通过配置指定。

如果 SDK 缓存了一些消息未发送,此时恰好业务服务器又重启,则所有缓存的消息将永久丢失,这种情况 SDK 不做处理,业务方需要针对某些非常关键的消息自己实现永久存储的功能。

2)消息存储可靠性

消息存储在 MySQL 中,每个分组有一主一备两台 MySQL 服务器,MySQL 服务器之间复制消息以保证消息存储高可用。如果主备间出现复制延迟,恰好此时 MySQL 主服务器宕机导致数据无法恢复,则部分消息会永久丢失,这种情况不做针对性设计,DBA 需要对主备间的复制延迟进行监控,当复制延迟超过 30 秒的时候需要及时告警并进行处理。

3)消息如何存储

每个消息队列对应一个 MySQL 表,消息队列名就是表名,表结构设计为……

4.3 设计规范

1)消息队列服务器使用 Spring Boot + Netty + mybatis 开发。

2)MySQL 使用 Innodb 存储引擎。

3)遵守公司一般项目的开发规范。

5. 质量设计


5.1 消息队列管理后台

1)可测试性:提供基于 http 协议的接口,测试同学可以根据规范使用 postman 等测试工具往消息系统发送消息,管理后台能够实时的查询到发送到平台的历史消息。

2)可维护性:遵循软件设计的"open-close"原则,核心接口对扩展开放,对修改关闭,确保每次的修改对核心链路不参数影响。

3)成本:项目基础框架使用开源项目及开源软件,无需额外的成本投入。

6. 演进规划

6.1 消息系统一期

一期支持点到点的消息推送,解决单系统到单系统的异步通信。

6.2 消息系统二期

支持点到多点的消息推送,解决单系统到多系统的异步通信。

支持延时消息的发送。

支持消息的自动重试。

用户头像

关注

还未添加个人签名 2019.01.09 加入

还未添加个人简介

评论

发布
暂无评论
架构训练营模块3作业-消息队列架构设计