【项目日记】仿RabbitMQ实现消息队列 --- 模块设计

在这里插入图片描述

你要的答案不在书本里,
也不能靠别人来解决,
除非你想一辈子当小孩。
你必须在自我内部找到答案,
感受到该做的正确事情。
--- 《献给阿尔吉侬的花束》---

仿RabbitMQ实现消息队列

  • 1 数据管理模块
    • 1.1 交换机数据管理模块
    • 1.2 队列数据管理模块
    • 1.3 绑定数据管理模块
    • 1.4 消息数据管理模块
    • 1.5 虚拟机数据管理模块
  • 2 功能模块
    • 2.1 路由匹配模块
    • 2.2 消费者管理模块
    • 2.3 信道管理模块
    • 2.4 连接管理模块
  • 3 服务器模块
  • 4 客户端模块
  • 5 模块关系图

1 数据管理模块

1.1 交换机数据管理模块

交换机需要管理的成员:描述了一个交换机应该有什么数据

  • 交换机名称:唯一标识
  • 交换机类型:决定消息的转发方式,每个队列绑定中有个binding_key ,每条消息中有个routing_key :
    1. 直接交换Directbinding_keyrouting_key 一致,将消息放入队列中。
    2. 广播交换Fanout:将消息放入交换机绑定的所有队列中。
    3. 主题交换Topicrouting_key与多个绑定队列的binding_key有个匹配规则,匹配成功则放入
  • 持久化标志:决定了当前交换机信息是否需要持久化储存。
  • 自动删除标志:关联了当前交换机的所有客户端都退出了,是否需要自动删除交换机。
  • 交换机其他参数

对交换机的管理操作

  1. 创建交换机:本质上是需要声明,强断言的思想:有就直接用,没有就创建
  2. 删除交换机:每个交换机都会绑定一个或多个队列(意味着会有一个或多个绑定信息),因此删除交换机需要删除相关绑定信息。
  3. 获取指定名称交换机
  4. 获取当前交换机数量

1.2 队列数据管理模块

队列要管理的数据:

  1. 队列名称:队列的唯一标识
  2. 持久化储存标志:决定了是否将队列信息持久化的储存起来,决定了重启后,这个队列还是是否存在,也决定了队列中的消息是否需要持久化。
  3. 是否独占标志:独占指的是只有当前客户端自己可以订阅队列消息
  4. 自动删除标志:当订阅了当前队列的所有客户端退出后,是否删除队列。
  5. 其他参数

对队列进行的管理操作依旧是增删查:

  1. 创建队列
  2. 删除队列
  3. 获取指定队列信息
  4. 获取队列数量
  5. 获取所有队列名称:当系统重启后,需要重新加载数据,加载历史消息(消息以队列为单元储存在文件中),而加载消息需要知道队列名称!因为后边消息储存的时候,储存文件已队列名称进行的取名 。

一个队列如果持久化标志为false,则意味着重启后队列就没了,也就没有客户端能够订阅队列的信息,因此这个队列的消息如果持久化储存了,是没有意义的。因此通常一个队列的持久化标志是false,那么它的消息也就不需要持久化处理!

1.3 绑定数据管理模块

描述一下将哪个队列与哪个交换机绑定在一起。
管理的数据:

  1. 交换机名称
  2. 队列名称
  3. binding_key:绑定密钥–描述了在交换机的主题交换&直接交换的消息发布匹配规则。由数字,字符,_#.

对绑定数据管理操作:

  1. 添加绑定
  2. 解除绑定
  3. 获取交换机相关的所有绑定信息:方便删除交换机时删除相关绑定信息。当消息发布到交换机,交换机得通过这些信息来将消息发布到指定队列
  4. 获取队列相关的所有绑定信息:方便删除队列时删除相关的绑定信息
  5. 获取绑定信息数量

1.4 消息数据管理模块

一条消息中应该包含哪些信息:

  1. 消息属性:
    • ID:消息的唯一标识
    • 持久化标志:表示是否对该消息进行持久化
    • routing_key:决定了当前消息要发布的队列(消息发布到交换机后,根据绑定队列的binding_key决定是否发布到指定队列)
  2. 消息主体:消息的内容
  3. 服务器为了管理所添加的信息
    • 储存偏移量:消息一队列为单元储存在文件中这个偏移量,是当前消息相对于文件起始位置的偏移量
    • 消息长度:从偏移量位置取出指定长度的消息(解决粘包问题)
    • 是否有效标志位:标识当前消息是否已经被删除(删除一条消息,并不会每次直接将后边的数据拷贝到前边,而只是重置了标志位。当一个文件中,有效消息占比不足50%时,且数据量超过2000,则进行垃圾回收,重新整理文件数据储存,将有效数据读取处理,然后重新截断文件,将消息连续的写入文件中!重启系统也只需要重新加载有效信息即可)

消息的管理方式:以队列为单元进行管理(因为消息的所有操作都是以队列为单元的)
针对消息的管理操作:

  1. 消息链表 :保存所有的待推送消息。
  2. 待确认消息hash:消息推送给客户端,会等待客户端进行消息确认,收到确认后,才会真正删除消息!
  3. 持久化消息hash:假设消息都会进行持久化储存,操作过程中会存在垃圾回收操作,但是垃圾回收会改变消息存储位置的!所以每次垃圾回收之后都要重新更新消息的属性!
  4. 持久化的有效消息数量
  5. 持久化的总消息数量:决定了什么时候进行垃圾回收!

对消息数据的管理操作:

  1. 向队列中新增消息
  2. 获取队首消息:获取消息后,就会从消息从消息链表中删除(不再是待发送消息,而是待确认消息),加入到待确认消息中
  3. 确认消息:从待确认消息中移除消息,并进行持久化数据的删除!
  4. 恢复队列历史消息:主要是在构造函数中进行(只有在重启的时候才会进行)
  5. 垃圾回收(消息持久化子模块完成):持久化文件中有效消息比例小于50%,且总消息数量超过200进行垃圾处理
  6. 删除队列相关消息文件:当一个队列被删除了,那他的消息也就没有存在的意义了!

队列消息管理:

  • 初始化队列消息结构
  • 移除队列消息结构:在一个队列创建/删除时进行调用
  • 向队列新增消息
  • 对队列消息进行确认
  • 恢复队列历史消息

1.5 虚拟机数据管理模块

虚拟机数据管理是对:交换机+队列+绑定+消息的数据管理的集合
需要管理的数据:

  1. 交换机数据管理句柄
  2. 队列数据管理句柄
  3. 绑定信息管理句柄
  4. 消息数据管理句柄

需要进行的管理操作

  1. 声明/删除交换机:注意在删除交换机的时候要删除相关的绑定信息
  2. 声明/删除队列:注意在删除队列的时候,要删除相关的绑定信息以及消息数据
  3. 队列的绑定/解除绑定:注意绑定的时候,交换机与队列是存在的!
  4. 获取指定队列的信息
  5. 对指定队列的指定消息进行确认
  6. 获取交换机相关的所有绑定信息:一条消息要发布给指定交换机的时候,交换机获取所有绑定信息,来确定消息要发布到哪个队列。

2 功能模块

2.1 路由匹配模块

路由匹配模块决定了一条消息是否能够发布到指定的队列中。在每个队列和交换机的绑定信息中都有一个binding_key :这是队列发布的匹配规则。在每条要发布的消息中都有一个routing_key:这是消息的发布规则。
交换机有三种交换类型:直接,广播,主题。

  1. 直接交换Directbinding_keyrouting_key 一致,将消息放入队列中。
  2. 广播交换Fanout:将消息放入交换机绑定的所有队列中。
  3. 主题交换Topicrouting_key与多个绑定队列的binding_key有个匹配规则,匹配成功则放入

路由匹配模块本质上来说没有要管理的数据,只有向外提供的路由匹配操作:

  • 提供一个判断routing_keybinding_key是否能够匹配成功的接口
  • 判断routing_key是否符合规定:格式约定:只能由数字,字母,_ . 构成
  • 判断binding_key是否符合规定:格式约定:只能由数字,字母,_ . # *构成

2.2 消费者管理模块

客户端有两种:发布消息客户端,订阅消息客户端。因此订阅了指定队列消息的客户端才是一个消费者

消费者数据存在的意义:当指定队列有了消息之后,就需要将消息推送给这个消费者客户端(推送的时候就需要找到这个客户端相关的信息—连接)!

消费者信息:

  1. 消费者标识tag
  2. 订阅队列名称:当当前队列有消息就会推送给当前客户端,以及当客户端收到消息,需要对指定队列的消息进行确认
  3. 自动确认标志:
    • 自动确认—推送消息后直接删除消息不需要额外确认。
    • 手动确认—推送消息后,需要等到消息确认回复之后再去删除消息。
  4. 消费处理回调函数指针:队列有一条消息之后,通过哪个函数进行处理(函数内部其实逻辑是固定的—向指定客户端推送消息)

消费者管理思想:

  • 以队列为单元进行管理,每个消费者订阅的都是指定队列的消息,消费者对消息进行确认也是以队列进行确认。
  • 最关键的是:当指定队列中有消息了,必然是获取订阅了这个队列的消费者信息进行消息推送

队列消费者管理结构:

  • 数据信息:消费者链表—保存当前队列的所有消费者信息(RR轮转思想,每次取出下一个消费者进行消息推送,一个消息只需要被一个客户端处理即可)
  • 管理操作:
    1. 新增消费者
    2. RR轮转获取一个消费者
    3. 删除消费者
    4. 队列消费者数量
    5. 是否为空

整体的管理操作:

  1. 初始化队列消费者结构
  2. 删除队列消费者结构
  3. 向直到队列添加消费者
  4. 获取指定队列消费者
  5. 删除指定队列消费者

2.3 信道管理模块

信道是网络通信中的一个概念,叫做通信通道。网络通信的时候,必然是通过网络通信连接来完成的,为了能够更加充分的利用资源,因此对通信连接又进行了一次细化,细化出了通信通道,对于用户来说,一个通信通道,就是进行网络通信的载体,而一个真正的通信连接,可以创造出多个通信通道!

每一个信道之间,在用户眼中是相互独立的,而本质的底层它们使用同一个通信连接进行网络通信!
因此,信道是用户眼中的一个通信通道。所以所有的网络通信服务都是由信道提供的 !

信道提供的服务操作:

  1. 声明/删除交换机
  2. 声明/删除队列
  3. 绑定/解绑队列与交换机
  4. 发布消息/订阅队列消息/取消队列订阅/队列消息确认

信道要管理的数据:

  1. 信道关联的虚拟机句柄
  2. 信道管理的消费者句柄:当信道关闭的时候,所有关联的消费者订阅都要取消,相当于删除所有的相关消费者!
  3. 工作线程池句柄:一旦信道进行了消息发布操作到指定队列之后,从指定队列获取一个消费者,对这条消息进行消费(也就是将这条消息推送给一个客户端的操作交给线程池来执行!)。并发每个信道都有一个线程池,而是整个服务器有一个线程池,大家所有的信道都是通过同一个线程池进行一步操作的!

对信道的管理操作

  1. 创建一个信道
  2. 关闭一个信道
  3. 获取指定信道句柄

2.4 连接管理模块

连接就是网络通信连接。在网络通信连接中我们使用muduo库来实现底层通信,muduo库中本身就有Connection连接的概念和对象类。但是在我们的连接中,还有一个上层通道信道的概念(muduo库中的信道是底层管理Socket通信的),因此我们的Connection是对muduo库的Connection的二次封装,形成我们自己所需的连接管理!

管理的数据;

  1. muduo库的通信连接
  2. 当前连接关联的信道管理句柄

连接提供的操作

  1. 创建信道
  2. 关闭信道

管理的操作

  1. 新增连接
  2. 关闭连接
  3. 获取指定连接信息

3 服务器模块

这个模块是一个功能整合模块,整合以上所有模块。本质上并不提供实质的功能性操作,重要的是搭建网络通信服务器,实现与客户端网络通信,能够识别客户端请求,并提供客户端请求的处理服务。

管理信息:

  1. 虚拟机管理模块句柄:一个服务器有一个虚拟机,其他所有交换机,队列,绑定,消息的操作都是针对这个虚拟机进行的!
  2. 消费者管理模块句柄:一个服务器有一个消费者管理模块
  3. 通信连接管理模块与协议处理模块句柄:一个服务器有一套通信模块。
  4. 工作线程池句柄:一个服务器有一个工作线程池,其他所有的信道操作都是这一个线程池
  5. muduo库通信所需元素

4 客户端模块

客户端模块包含几个模块:消费者管理模块 ,信道管理模块

消费者管理模块需要:

  1. 消费者标识
  2. 订阅的队列名称
  3. 自动确认标志
  4. 消息回调函数函数指针:当消费者订阅了某一个队列的消息,这个队列有了这个消息之后,就会将消息推送给这个客户端,这时候收到了消息则使用回调函数进行处理,处理完毕后根据确认标志决定是否进行消息确认!

消费者管理模块管理的操作:增删查

信道管理模块:所有提供的操作与服务端雷同,因为客户端给用户要提供什么服务,服务器就要给客户端通过什么服务!

信道管理模块管理的信息有:

  1. 消费者管理模块:每个信道都要有自己的相关消费者
  2. 线程池句柄:对推送过来的消息进行回调处理,处理过程通过工作线程来进行
  3. 信道关联的连接。

信道提供的服务 :

  1. 声明/删除交换机
  2. 声明/删除队列
  3. 绑定/解绑队列与交换机
  4. 发布消息/确认消息
  5. 订阅队列消息/取消订阅队列消息
  6. 创建/关闭信道

信道的管理:增删查

连接管理模块:客户端连接的管理,本质上是对客户端TcpClient的二次封装和管理。面对用户来说,不需要有客户端的概念,连接对应用户来说就是客户端,通过连接创建信道,通过信道完成自己的所需服务。因此当前客户端这边的连接,对于用户来说就是一个资源的载体!

管理的资源:工作线程池,连接关联的信道管理句柄
管理的操作:

  1. 连接服务器
  2. 创建信道
  3. 关闭信道
  4. 关闭连接

异步工作池模块:

  1. TcpClient模块需要一个EventLoopThread模块进行IO事件监控
  2. 收到推送消息后,需要对推送过来的消息进行处理,因此需要一个线程池来帮助我们完成消息处理的过程!

将异步线程池模块单独拎出来,是因为多个连接用一个EventLoopThread进行IO事件监控就够了,以及所有的推送消息也只需要一个线程池就够了!并不需要每个连接都要有一个工作线程池!

5 模块关系图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/972609.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ Primer 构造函数再探

欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…

SQL 注入攻击详解[基础篇]:Web 应用程序安全漏洞与防御策略

目录 SQL注入的简介 现代 Web 应用程序中的数据库交互与 SQL 注入攻击 数据库管理系统(DBMS)架构与 SQL 注入 什么是 SQL 注入? SQL 注入的工作原理 SQL 注入的用例与影响 如何预防 SQL 注入? 数据库分类 数据库类型&am…

自制AirTag,支持安卓/鸿蒙/PC/Home Assistant,无需拥有iPhone

苹果的AirTag很贵,虽然某强北有平价代替品,但是仍需要苹果设备才能绑定,才能查看位置。不支持安卓/鸿蒙/PC,也不支持集成到Home Assistant中。 AirTag 的原理 每个AirTag都会发送一个蓝牙信号,其可以被临近的苹果设备…

网络技术变迁:从IPv4走向IPv6

目录 前言 旧时代产物:IPv4 什么是IPv4? IPv4的工作方式 IPv4的缺点 为什么要从IPv4过渡到IPv6? 走向IPv6:新一代互联网协议 IPv6的技术特性 我们需要过渡技术 双栈(Dual Stack) 隧道技术&#…

uniapp 滚动尺

scale组件代码&#xff08;部分class样式使用到了uview1.0的样式&#xff09; <template><view><view class"scale"><view class"pointer u-flex-col u-col-center"><u-icon name"arrow-down-fill" size"26&qu…

模型量化初始知识

原文网址&#xff1a;知乎原文-量化基础知识 背景 PyTorch对量化的支持目前有如下三种方式&#xff1a; Post Training Dynamic Quantization&#xff0c;模型训练完毕后的动态量化&#xff1b; Post Training Static Quantization&#xff0c;模型训练完毕后的静态量化&…

在项目中调用本地Deepseek(接入本地Deepseek)

前言 之前发表的文章已经讲了如何本地部署Deepseek模型&#xff0c;并且如何给Deepseek模型投喂数据、搭建本地知识库&#xff0c;但大部分人不知道怎么应用&#xff0c;让自己的项目接入AI模型。 文末有彩蛋哦&#xff01;&#xff01;&#xff01; 要接入本地部署的deepsee…

Redis7——基础篇(五)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…

【爬虫基础】第一部分 网络通讯 P1/3

前言 1.知识点碎片化&#xff1a;每个网站实现的技术相似但是有区别&#xff0c;要求我们根据不同的网站使用不同的应对手段。主要是常用的一些网站爬取技术。 2.学习难度&#xff1a;入门比web简单&#xff0c;但后期难度要比web难&#xff0c;在于爬虫工程师与网站开发及运维…

揭秘区块链隐私黑科技:零知识证明如何改变未来

文章目录 1. 引言&#xff1a;什么是零知识证明&#xff1f;2. 零知识证明的核心概念与三大属性2.1 完备性&#xff08;Completeness&#xff09;2.2 可靠性&#xff08;Soundness&#xff09;2.3 零知识性&#xff08;Zero-Knowledge&#xff09; 3. 零知识证明的工作原理4. 零…

R软件用潜在类别混合模型LCM分析老年人抑郁数据轨迹多变量建模研究

全文链接&#xff1a; tecdat.cn/?p40283 潜在类别混合模型假设总体具有异质性&#xff0c;由 GG 个潜在类别组成。在多变量的情况下&#xff0c;潜在类别是根据 KK 个纵向结果来定义的&#xff0c;从而形成 GG 个组&#xff0c;每个组的特征由 KK 个轨迹均值轮廓集表示&#…

【Rust中级教程】1.11. 生命周期(进阶) Pt.1:回顾、借用检查器、泛型生命周期

喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 这篇文章在Rust初级教程的基础上对生命周期这一概念进行了补充&#xff0c;建议先看【Rust自…

【DeepSeek服务器部署全攻略】Linux服务器部署DeepSeek R1模型、实现API调用、搭建Web页面以及专属知识库

DeepSeek R1模型的Linux服务器搭建、API访问及Web页面搭建 1&#xff0c;引言2&#xff0c;安装Ollama工具3&#xff0c;下载DeepSeek R1 模型4&#xff0c;DeepSeek命令行对话5&#xff0c;DeepSeek API接口远程调用6&#xff0c;DeepSeek结合Web-ui实现图形化界面远程访问6.1…

【免费软件分享】Typor1.9.5-x64-CN免费版

到处找pojie软件的朋友&#xff0c;这里给大家提供一个版本&#xff0c;之前也是废了老大的劲才找到&#xff0c;这里分享给大家&#xff0c;希望帮助到需要的朋友&#xff01; Typor1.9.5-x64-CN&#xff1a; 我用夸克网盘分享了「Typor1.9.5-x64-CN.7z」&#xff0c;点击链接…

Python天梯赛刷题-五分题(上)

蓝桥杯题刷的好累&#xff0c;感觉零帧起手、以题带学真的会很吃力&#xff0c;打算重新刷一点天梯的题目巩固一下&#xff0c;我本人在算法非常不精通的情况下&#xff0c;自认为天梯的L1的题是会相对容易一些的&#xff0c;可能有一些没有脑子光靠力气的“硬推”hhhh。 从头…

Python编程之数据分组

有哪些方式可以进行数据分组利用Pandas库进行分组使用itertools库的groupby分组操作构建Python字典方式实现(小规模数据,不适用数量特别大的情况,不需要依赖其它python库)利用NumPy的groupby函数分组操作利用Python的Dask库提供的函数进行分组下面看一个如何去实现坐标数据…

激光雷达YDLIDAR X2 SDK安装

激光雷达YDLIDAR X2 SDK安装 陈拓 2024/12/15-2024/12/19 1. 简介 YDLIDAR X2官方网址https://ydlidar.cn/index.html‌YDLIDAR X2 YDLIDAR X2是一款高性能的激光雷达传感器&#xff0c;具有以下主要特点和规格参数‌&#xff1a; ‌测距频率‌&#xff1a;3000Hz ‌扫描频…

大数据组件(四)快速入门实时数据湖存储系统Apache Paimon(2)

大数据组件(四)快速入门实时数据湖存储系统Apache Paimon(2) 我们上次已经了解了Paimon的下载及安装&#xff0c;并且了解了主键表的引擎以及changelog-producer的含义 大数据组件(四)快速入门实时数据湖存储系统Apache Paimon(1) 今天&#xff0c;我们继续快速了解下最近比…

⭐ Unity 横向滑动列表 首尾相连 轮转图

效果如下&#xff1a; 场景挂载&#xff1a; 代码部分&#xff1a; using DG.Tweening; using System; using System.Collections; using System.Collections.Generic; using System.Drawing.Printing; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine…

大白话实战Sentinel

Sentinel是SpringCloudAlibaba提供的用来做服务保护的框架,而服务保护的常见手段就是限流和熔断降级。在大型分布式系统里面,由于微服务众多,所以服务之间的稳定性需要做特别关注,Sentinel的核心包就提供了从多个维度去保护服务稳定的策略,而且这些保护策略都可以连接上Se…