当前位置: 首页 > news >正文

从零手搓一个【消息队列】项目设计、需求分析、模块划分、目录结构

文章目录

  • 一、需求分析
    • 1, 项目简介
    • 2, BrokerServer 核心概念
    • 3, BrokerServer 提供的核心 API
    • 4, 交换机类型
    • 5, 持久化存储
    • 6, 网络通信
    • 7, TCP 连接的复用
    • 8, 需求分析小结
  • 二、模块划分
  • 三、目录结构


提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之处欢迎批评指点~ 废话不多说,直接上干货!

一、需求分析

1, 项目简介

之前我的 这篇文章 中介绍过 JUC 中的阻塞队列 BlockingQueue , 介绍过"生产者消费者模型", 在实际开发中, 尤其是分布式系统⾥, 跨主机之间使⽤⽣产者消费者模型, 也是⾮常普遍的需求

因此, 我们通常会把阻塞队列, 封装成⼀个独⽴的服务器程序, 并且赋予其更丰富的功能, 这样的程序我们就称为 消息队列 (Message Queue, MQ)

目前市场上比较成熟的消息队列有: kafka, RabbitMQ, RocketMQ…, 本项目中部分参考 RabbitMQ 和 “AMQP 协议” 进行设计

项目描述 : 可跨主机的生产者消费者服务器程序,用于服务器之间的解耦,流量削峰;使用RPC模式,由客户端发送网络请求,远程调用服务器以操作交换机、队列、发布消息、订阅消息等;由服务器实现相关逻辑、持久化存储、异步转发消息等

所以这个项目中有一些比较核心的概念和模块 :

  • 生产者(Producer) 负责往消息队列中投入消息
  • 消费者(Consumer) 负责从消息队列中消费消息
  • 中间人(Broker) 负责消息的存储和转发
  • 发布(Publish) 投入消息的过程
  • 订阅(Subscribe) 消费者注册一个队列的过程(我想要这个队列里的消息)

消费者消费数据由两种模式 :
1, 消费者从队列里取, 这种模式称为"拉"
2, 队列里有消息时, Broker (中间人服务器) 给消费者推送消息, 这种模式称为"推"
我们的项目中实现 “推” 这种模式

Producer, Consumer, Broker 都是服务器程序, 需要编写代码支持这三者之间的业务逻辑

但 Producer, Consumer 又是广义上的消费者, Producer, Consumer 是发起请求的一方, 所以是客户端, Broker 是返回响应的一方, 所以是服务器
在这里插入图片描述
在这里插入图片描述


2, BrokerServer 核心概念

  • 虚拟机 (VirtualHost): 是⼀个逻辑上的集合, ⼀个 BrokerServer 上可以存在多个 VirtualHost , 如果一个 BrokerServer 有多个业务线, 就可以用不同的 VirtualHost 在分别组织不同类别的数据(我们的项目中暂时只设定一个VirtualHost)
  • 交换机 (Exchange): ⽣产者把消息先发送到 Broker 的 Exchange 上. 再根据不同的规则, 把消息转发给不同的 Queue
  • 队列 (Queue): 真正⽤来存储消息的部分. 每个消费者决定⾃⼰从哪个 Queue 上取消息
  • 绑定 (Binding): Exchange 和 Queue 之间的关联关系.
  • 消息 (Message): 传递的内容.

用数据库做对比:
VirtualHost 相当于 database, Exchange 和 Queue 都是 table, Exchange 和 Queue 可理解成 “多对多” 关系. 所以 Binding 就是一个中间表, 可以把这两张表联系起来

在这里插入图片描述

AMQP 协议就是按照上述格式组织


3, BrokerServer 提供的核心 API

Producer, Consumer 是发起请求的一方, 所以是客户端, Broker 是返回响应的一方, 所以是服务器
因此 BrokerServer 需要给 Producer, Consumer 提供一些核心 API (对外暴露的), 这些 API 用来实现整个消息队列支持的基本功能

  • 1, 创建队列 queueDeclare (Declare 表示不存在则创建, 存在则不创建)
  • 2, 销毁队列 queueDelete
  • 3, 创建交换机 exchangeDeclare
  • 4, 销毁交换机 exchageDelete
  • 5, 创建绑定 queueBind
  • 6, 解除绑定 queueUnbind
  • 7, 发布消息 basicPublish
  • 8, 订阅消息 basicSubscribe (只是告知服务器有个消费者需要这个队列的数据)
  • 9, 确认消息 basicAck (让消费者显式的告诉服务器, 收到并处理了消息

我们的项目给消费者在订阅消息时, 提供 “自动应答” 和 “确认应答” 两种方式

还有 “拒绝应答” 这种方式, 本项目暂未实现

没有 “消费消息” 这个 API , 上文已经说明, 我们的项目中不支持消费者主动从队列中取消息, 而是由服务器推送给消费者**(这个过程有些复杂, 后续会详细介绍)**

在这里插入图片描述


4, 交换机类型

  • 直接交换机 Direct
  • 扇出交换机 Fanout
  • 主题交换机 Topic
  • 消息头交换机 Header

咱们的项目不实现第四种, 实现方式复杂且比较少见

生产者在发布消息时, 有三个参数: 1, 消息 2, 交换机 3, routingKey (下面介绍), 不同的交换机有不同的转发规则

主题交换机: 不需要和队列建立绑定, 生产者发布消息时, routingKey 作为队列名(唯一标识), 如果队列存在, 交换机直接把消息投入到该队列中

扇出交换机: 需要和队列建立绑定, 生产者发布消息时什么都不用做 routingKey 为 null, 交换机会把消息给已绑定的队列都投送一份

主题交换机: 需要和队列建立绑定, 并且绑定的时候指定一个交换机和队列之间的 “暗号” bindingKey, 生产者发布消息的时候指定一个 “暗号” routingKey, 交换机会把消息投送给已绑定的队列中, 暗号能够对上(规则匹配)的那个队列

Binding 表中就记录了 交换机和队列的绑定关系, 以及 bindingKey
目前不需要全部看懂 Binding 表, 大概熟悉这三种绑定规则即可

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


5, 持久化存储

上述提到的交换机, 队列, 绑定, 消息 需要在硬盘和内存上各存储一份, 内存为主, 硬盘为辅

因为内存的访问速度快, 而这对消息队列这个项目, 效率更重要, 而硬盘存储是为了服务器重启之后数据不丢失

硬盘存储使用 数据库 + 文件的方式, 数据库中存储 交换机, 队列, 绑定, 文件中存储消息

因为数据库提供的 增, 删, 查 比较方便, 交换机, 队列, 绑定正需要这些操作, 而消息不需要大量, 复杂的增删查, 基本只涉及到存储, 所以使用数据库略显"多余", 而且一旦消息很多之后, 数据库的性能也有限


6, 网络通信

生产者消费者作为客户端程序, 和 BrokerServer 通过网络进行通信和交互

后续会自定义应用层协议, 传输层使用 TCP 的 Socket API

上述介绍过 BrokerServer 提供的一些核心 API , 在生产者消费者程序上也需要提供的相应的 API

以创建队列这个操作为例: 客户端调用 queueDeclare(), 客户端的这个方法只是实现了向服务器发送请求, 让服务器调用服务器的 queueDeclare() , 服务器的这个方法实现了真正创建交换机, 并持久化存储, 然后返回给客户端一个响应, 告知客户端执行成功了没有

在这里插入图片描述

由于客户端也有 queueDeclare() , 客户端看起来是在调用自己的 queueDeclare() 从而创建出来了队列, 实际上是通过网络请求, 调用了服务器的 queueDeclare() , 而服务器是怎么做的, 客户端并不知道细节

这种方式称作: 远程过程调用(RPC)


7, TCP 连接的复用

上面说到要在生产者消费者客户端提供 BrokerServer 的核心 API :

  • 1, 创建队列 queueDeclare (Declare 表示不存在则创建, 存在则不创建)
  • 2, 销毁队列 queueDelete
  • 3, 创建交换机 exchangeDeclare
  • 4, 销毁交换机 exchageDelete
  • 5, 创建绑定 queueBind
  • 6, 解除绑定 queueUnbind
  • 7, 发布消息 basicPublish
  • 8, 订阅消息 basicSubscribe (只是告知服务器有个消费者需要这个队列的数据)
  • 9, 确认消息 basicAck (让消费者显式的告诉服务器, 收到并处理了消息

由于一次 TCP 连接与断开 需要经过三次握手四次挥手, 一个客户端有可能短时间内持续使用 RPC 模式远程调用 BrokerServer 的 API, 这就需要多次 TCP 的连接和断开

所以引入 Channel (信道) 的概念, 建立 TCP 连接之后, 可以使用一个 Channel表示一次逻辑上的连接(一次请求和响应), 一个 Connection 中包含多个 Channel , 各个 Channel 中的数据互不相干, 实现一次 TCP 连接的复用

所以生产者客消费者(客户端)还需要提供四个 API

  • 10, 创建 Connection (建立 TCP 连接)
  • 11, 关闭 Connection (关闭 TCP 连接)
  • 12, 创建 Channel (建立逻辑上的连接)
  • 13, 关闭 Channel (关闭逻辑上的连接)

8, 需求分析小结

  • 1, 生产者客户端, 消费者客户端, BrokerServer 服务器这三个板块, 这三者都是服务器程序
  • 2, 生产者消费者 的代码主要围绕 “网络通信” 展开
  • 3, BrokerServer 的代码主要围绕 “核心概念” , "核心 API " , “数据管理” 展开

在这里插入图片描述


二、模块划分

在这里插入图片描述

三、目录结构

这里各位大概率是一眼看不懂的, 只需要结合注释大致了解各个包和类是用来做什么的即可

由于项目略微复杂, 先对整体结构有个大致认知, 从下篇开始会详细介绍代码编写
在这里插入图片描述

相关文章:

从零手搓一个【消息队列】项目设计、需求分析、模块划分、目录结构

文章目录 一、需求分析1, 项目简介2, BrokerServer 核心概念3, BrokerServer 提供的核心 API4, 交换机类型5, 持久化存储6, 网络通信7, TCP 连接的复用8, 需求分析小结 二、模块划分三、目录结构 提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之…...

【Spring Cloud】深入探索 Nacos 注册中心的原理,服务的注册与发现,服务分层模型,负载均衡策略,微服务的权重设置,环境隔离

文章目录 前言一、初识 Nacos 注册中心1.1 什么是 Nacos1.2 Nacos 的安装,配置,启动 二、服务的注册与发现三、Nacos 服务分层模型3.1 Nacos 的服务分级存储模型3.2 服务跨集群调用问题3.3 服务集群属性设置3.4 修改负载均衡策略为集群策略 四、根据服务…...

No156.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…...

如何在PIL图像和PyTorch Tensor之间进行相互转换,使用pytorch进行PIL和tensor之间的数据转换

目录 引言PIL简介PyTorch和Torchvision简介PIL转换为TensorTensor转换为PIL实例代码和解释结论参考文献 📝 引言 在计算机视觉领域,使用图像处理库对图像进行预处理是非常常见的。其中,Python Imaging Library(PIL)以…...

STM32F4X UCOSIII任务消息队列

STM32F4X UCOSIII任务消息队列 任务消息队列和内核消息队列对比内核消息队列内核消息队列 UCOSIII任务消息队列API任务消息队列发送函数任务消息队列接收函数 UCOSIII任务消息队列例程 之前的章节中讲解过消息队列这个机制,UCOSIII除了有内核消息队列之外&#xff0…...

8个居家兼职,帮助自己在家搞副业

越来越多的人开始追求居家工作的机会,无论是为了获得更多收入以改善生活质量,还是为了更好地平衡工作和家庭的关系,居家兼职已成为一种趋势。而在家中从事副业不仅能够为我们带来额外的收入,更重要的是,它可以让我们在…...

管理与系统思维

技术管理者不仅仅需要做事情,还需要以系统思维的方式推动组织变革,从而帮助团队和个人做到更好。原文: Management and Systems Thinking 图片来源: Dall-E "除非管理者考虑到组织的系统性,否则大多数提高绩效的努力都将注定失败。"…...

电死人的是电流还是电压?

先说答案,是电流。 这个有两个派别,一个是电流派,一个是电压派。 举个例子,拿我们的头发或者指甲之类的高电阻物质去接触高压,你会发现基本没有什么作用;还有就是冬天我们脱毛衣的时候,噼里啪啦…...

mac 编译问题记录

1、mac 编译提示 Unsupported option ‘--no-pie‘ Linux 上用 --no-pie mac 上用 -no-pie 2、mac 找不到 malloc.h 使用 #include <sys/malloc.h> Mac上使用malloc函数报错_mac malloc.h-CSDN博客...

centos 7.9同时安装JDK1.8和openjdk11两个版本

1.使用的原因 在服务器上&#xff0c;有些情况因为有一些系统比较老&#xff0c;所以需要使用JDK8版本&#xff0c;但随着时间的发展&#xff0c;新的软件出来&#xff0c;一般都会使用比较新的JDK版本。所以就出现了我们标题的需求&#xff0c;一个系统内同时安装两个不同的版…...

【JavaEE】HTML

JavaWeb HTML 超文本标记语言 超文本&#xff1a;文本、声音、图片、视频、表格、连接标记&#xff1a;有许许多多的标签组成 vscode开发工具搭建 因为我使用的IDEA是社区版&#xff0c;代码高亮补全缩进都有些问题&#xff0c;使用vscode是最好的选择~ 安装 Visual Stu…...

【数据结构--八大排序】之堆排序

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

c# 中的类

反射 Activator.CreateInstance class Program {static void Main(string[] args){//反射Type t typeof(Student);object o Activator.CreateInstance(t, 1, "FJ");Student stu o as Student;Console.WriteLine(stu.Name);//动态编程dynamic stu2 Activator.Cre…...

基于单片机的煤气泄漏检测报警装置设计

一、项目介绍 煤气泄漏是一种常见的危险情况&#xff0c;可能导致火灾、爆炸和人员伤亡。为了及时发现煤气泄漏并采取相应的安全措施&#xff0c;设计了一种基于单片机的煤气泄漏检测报警装置。 主控芯片采用STM32F103C8T6作为主控芯片&#xff0c;具有强大的计算和控制能力。…...

[导弹打飞机H5动画制作] 导弹每次飞行的随机路线制作

技术核心提示: 第一步:检测引导层插件是否具备,如果没有手工添加: createjs.MotionGuidePlugin.install(); 第二步:增加全局变量: var fValue=0; var iOddEven =0; var missileObj=null; 第三步:填写 第一帧 代码: if (missileObj)stage.removeChild(missileObj);missile…...

OpenCV实现FAST算法角点检测 、ORB算法特征点检测

目录 1 Fast算法 1.1 Fast算法原理 1.2 实现办法 1.2.1 机器学习的角点检测器 1.2.2 非极大值抑制 1.3 代码实现 1.4 结果展示 2 &#xff0c;ORB算法 2.1代码实现 2.2 结果展示 1 Fast算法 1.1 Fast算法原理 1.2 实现办法 1.2.1 机器学习的角点检测器 1.2.2 …...

【Unity的 Built-in 渲染管线下实现好用的GUI模糊效果_Blur_案例分享(内附源码)】

CGPROGRAM实现好用的GUI模糊效果 实现Blur模糊方式1C#代码如下方式1_Shader代码如下实现Blur模糊方式2方式2_Shader如下实现Blur模糊方式1 其他的模糊效果,在这一篇。 效果如图: 新建一个C#文件,命名为"CommandBlur",打开C#,删除内容,复制粘贴下面的代码:…...

AR智能眼镜:提升现场服务技能、效率与盈利能力的利器(一)

随着技术的不断进步&#xff0c;现场服务组织正朝着远程支持转变&#xff0c;用以解决技能差距和生产力问题&#xff0c;提高员工培训和操作效率&#xff0c;同时为企业提高利润率&#xff0c;创造竞争优势。 本文将探讨增强现实&#xff08;AR&#xff09;、辅助现实&#xf…...

ChatGPT 在机器学习中的应用

办公室里一个机器人坐在人类旁边&#xff0c;Artstation 上的流行趋势&#xff0c;美丽的色彩&#xff0c;4k&#xff0c;充满活力&#xff0c;蓝色和黄色&#xff0c; DreamStudio出品 一、介绍 大家都知道ChatGPT。它在解释机器学习和深度学习概念方面也非常高效&#xff0c;…...

【JavaEE】锁策略

文章目录 前言1. 乐观锁和悲观锁2. 重量级锁和轻量级锁3. 自旋锁和挂起等待锁4. 公平锁和非公平锁5. 可重入锁和非可重入锁6. 读写锁Java synchronized 分别对应哪些锁策略1. 乐观锁和悲观锁2. 重量级锁和轻量级锁3. 自旋锁和挂起等待锁4. 公平锁和非公平锁5. 可重入锁和非可重…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...