消息队列架构设计文档
1. 业务背景
随着业务的不断发展,业务上拆分的子系统越来越多,目前系统间的调用都是同步调用,由此带来几个明显的系统问题:
性能问题:当涉及多个系统间调用时,需要同步等待各子系统串行调用,性能很低。
耦合问题:当新增一个子系统时,系统需要不断为新增子系统添加接口。
效率问题:每个子系统提供的接口参数和实现都有一些细微的差别,导致每次都需要重新设计接口和联调接口,开发团队和测试团队花费了许多重复工作量。
基于以上背景,我们需要引入消息队列进行系统解耦,将目前的同步调用改为异步通知。
2. 约束和限制
本次作业未有具体约束,因此假象为
1.研发时间不能超过 4 个月
2.成本不能超过 500 万
3.数据库采用 mysql
3. 总体架构
系统主体分为消息队列管理系统和消息队列系统,具体如下
消息队列系统内部架构
3.2 总体架构
采用多个数据集群分组的架构,各集群中的服务器进行分组,每个分组存储一部分消息
每个分组包含一台主 MySQL 和一台备 MySQL,分组内主备数据复制,分组间数据不同步。
正常情况下,分组内的主服务器对外提供消息写入和消息读取服务,备服务器不对外提供服务;主服务 宕机的情况下,备服务器对外提供消息读取的服务。
客户端采取轮询的策略写入和读取消息。
消息队列管理系统,负责消息队列的权限控制、队列上线/下线、流控、数据监控等功能
4. 详细设计
4.1 核心功能
4.1.1 消息发送流程
4.1.2 消息消费流程
4.2 关键设计
消息发送可靠性
业务服务器中嵌入消息队列系统提供的 SDK,SDK 支持轮询发送消息,当某个分组的主服务器无法发送消息时,SDK 挑选下一个分组主服务器重发消息,依次尝试所有主服务器直到发送成功;如果全部主服务器都无法发送,SDK 可以缓存消息,也可以直接丢弃消息,具体策略可以在启动 SDK 的时候通过配置指定。
如果 SDK 缓存了一些消息未发送,此时恰好业务服务器又重启,则所有缓存的消息将永久丢失,这种情况 SDK 不做处理,业务方需要针对某些非常关键的消息自己实现永久存储的功能。
消息存储可靠性
消息存储在 MySQL 中,每个分组有一主一备两台 MySQL 服务器,MySQL 服务器之间复制消息以保证消息存储高可用。如果主备间出现复制延迟,恰好此时 MySQL 主服务器宕机导致数据无法恢复,则部分消息会永久丢失,这种情况不做针对性设计,DBA 需要对主备间的复制延迟进行监控,当复制延迟超过 30 秒的时候需要及时告警并进行处理。
消息如何存储
每个消息队列对应一个 MySQL 表,消息队列名就是表名,表结构设计为消息 id、消息体、消息接收时间、消息、消息时效标志。
4.3 设计规范
消息队列服务器使用 Spring Boot + Netty 开发,采用 reactor 网络模型;服务端包含多个 sharding,每个 sharding 包含一主一从两台服务器,主服务器提供读写操作,从服务器仅提供读操作,主从服务基于 zookeeper 进行切换
MySQL 使用 Innodb 存储引擎,使用 mysql 的主从同步
消息表中的数据保留 30 天,超期自动清除
客户端与服务端采用 tcp 连接,socket 方式传输,数据格式为 json;同时增加 http 接口的调用,支持非 java 系统
消息队列管理端采用 springboot 开发,使用独立的 mysql 数据库存储权限、队列状态信息;配置多数据源读取消息队列系统的具体消息。
5. 质量设计
[必选,描述和质量相关的设计,包括:可测试性、可维护性、可观测性、成本等设计]
[样例:
可测试性:高。管理端独立开发,支持通过数据库写入、接口调用等方式,向消息队列系统中写入消息。并有对应的管理页面可以查询写入数据的内容、服务器负载、流量等信息
成本:中。使用多个 mysql 数据库服务,同时进行数据库服务器隔离、实例隔离方式,对应数据分组,成本即为数据库成本。管理端开发成本低,使用 springboot 支持管理端快速开发,增加对应读写消息接口即可,方案成熟。
6. 演进规划
[必选,可以是演进规划,也可以是项目计划,需要描述每个里程碑或者版本具体要实现的能力]
[样例:
一期上线需要满足 tps2000 的负载目标,数据可靠性 99.99%
二期需提高 tps 一倍,数据可靠性不降低。
三期着重提高同城多活、异地灾备架构,提高系统稳定性
评论