SpringAMQP WorkQueue消息队列模型的理解与使用

news2025/8/12 2:10:47

原理分析

Work Queue,故名思意,工作队列,互相配合工作。适用于消息密集型消息队列的场景,如下图所示,queue中存在着大量的消息,而消费者有续配合工作,消息队列有阅后即焚的特点,所以不会出现重复消费的情况。

在这里插入图片描述

工作队列属于一个设计模型的概念,并不是一项复杂的技术,简单来说就是一个消息队列绑定多个消费者。利用SpringAMQP,我们能很容易搭建出一个WorkQueue。

代码实现

从上面的图中,我们知道工作队列的设计要素:

  • queue中有大量的消息需要消费
  • 消费者有多个

基于上面的需求,我们再设计一个场景:

  • 消费者1的处理速度为每秒50条消息
  • 消费者2的处理速度为每秒5条
  • 生产者不限速

为什么要设计这个场景,一会再分析,我们先简单地搭一个小小的测试Demo。

生产者:

    @Test
    public void testWorkQueue() {
        String queueName = "work.queue";
        String message = "hello world!___";
        for(int i = 0; i < 50; i++) {
            rabbitTemplate.convertAndSend(queueName,message + i);
        }
    }

消费者1:

每秒处理50条

    @RabbitListener(queues = "work.queue")
    public void listenWorkQueue1(String msg) throws InterruptedException {
        System.out.println("20 listen:" + msg);
        Thread.sleep(20);
    }

消费者2:

每秒处理5条

    @RabbitListener(queues = "work.queue")
    public void listenWorkQueue2(String msg) throws InterruptedException {
        System.err.println("200 listen:" + msg);
        Thread.sleep(200);
    }

运行结果分析

在运行前,我们设想一下,一共50条消息,消费者1每秒能处理50条,消费者2每秒能处理5条,那总消费时长会是多少呢?消费者1处理消息多还是消费者2处理的消息多?

带着这个疑问去运行一下,下面的是我的控制台执行结果

200 listen:hello world!___0 time:10:50:53.070
20 listen:hello world!___1 time:10:50:53.070
20 listen:hello world!___3 time:10:50:53.098
20 listen:hello world!___5 time:10:50:53.130
20 listen:hello world!___7 time:10:50:53.165
20 listen:hello world!___9 time:10:50:53.196
20 listen:hello world!___11 time:10:50:53.228
20 listen:hello world!___13 time:10:50:53.251
20 listen:hello world!___15 time:10:50:53.284
200 listen:hello world!___2 time:10:50:53.284
20 listen:hello world!___17 time:10:50:53.316
20 listen:hello world!___19 time:10:50:53.352
20 listen:hello world!___21 time:10:50:53.383
20 listen:hello world!___23 time:10:50:53.415
20 listen:hello world!___25 time:10:50:53.435
20 listen:hello world!___27 time:10:50:53.473
200 listen:hello world!___4 time:10:50:53.489
20 listen:hello world!___29 time:10:50:53.508
20 listen:hello world!___31 time:10:50:53.541
20 listen:hello world!___33 time:10:50:53.577
20 listen:hello world!___35 time:10:50:53.610
20 listen:hello world!___37 time:10:50:53.641
20 listen:hello world!___39 time:10:50:53.671
200 listen:hello world!___6 time:10:50:53.704
20 listen:hello world!___41 time:10:50:53.704
20 listen:hello world!___43 time:10:50:53.736
20 listen:hello world!___45 time:10:50:53.767
20 listen:hello world!___47 time:10:50:53.802
20 listen:hello world!___49 time:10:50:53.835
200 listen:hello world!___8 time:10:50:53.907
200 listen:hello world!___10 time:10:50:54.127
200 listen:hello world!___12 time:10:50:54.335
200 listen:hello world!___14 time:10:50:54.553
200 listen:hello world!___16 time:10:50:54.769
200 listen:hello world!___18 time:10:50:54.983
200 listen:hello world!___20 time:10:50:55.183
200 listen:hello world!___22 time:10:50:55.384
200 listen:hello world!___24 time:10:50:55.586
200 listen:hello world!___26 time:10:50:55.803
200 listen:hello world!___28 time:10:50:56.017
200 listen:hello world!___30 time:10:50:56.227
200 listen:hello world!___32 time:10:50:56.442
200 listen:hello world!___34 time:10:50:56.655
200 listen:hello world!___36 time:10:50:56.872
200 listen:hello world!___38 time:10:50:57.074
200 listen:hello world!___40 time:10:50:57.285
200 listen:hello world!___42 time:10:50:57.491
200 listen:hello world!___44 time:10:50:57.698
200 listen:hello world!___46 time:10:50:57.912
200 listen:hello world!___48 time:10:50:58.118

结果分析
回答一下上面的疑问,总消费时长:10:50:58.118 - 10:50:53.070 ,大概是5秒左右,两个线程都分别消费了25条,而且是有序地消费,消费者1的是单数,消费者2的是双数。

这个结果我们并不满意,消费者1的速度是消费者的速度的10倍,我为啥要把活平分呢?这个与轮询机制效果很相似,但是在消息队列里它不叫轮询,叫做消息预取。消费者1与消费者2会提前获得消息的分配。按照我们理想的状态,消费者1其实自己1秒就能把活给都干了,和消费者2合作之后,反而还加长到了5秒!那我加多一个消费者干嘛?

解决方案

针对这个问题,我们会考虑,能不能让这消费者2干不了就别接这么多活?答案是可以的,而且很容易,只需在添加一下配置文件
application.yml

spring:
  rabbitmq:
    listener:
      simple:
        prefetch: 1 # 每次只能获取1条

prefetch就是预取的意思,默认值是无限,有多少就拿多少,在这里限制它每次只能预取1条,那就可以限制消费者2干不了又揽太多活的现象了。

再执行一次,查看结果

200 listen:hello world!___0 time:11:25:50.496
20 listen:hello world!___1 time:11:25:50.496
20 listen:hello world!___2 time:11:25:50.527
20 listen:hello world!___3 time:11:25:50.558
20 listen:hello world!___4 time:11:25:50.589
20 listen:hello world!___5 time:11:25:50.622
20 listen:hello world!___6 time:11:25:50.653
20 listen:hello world!___7 time:11:25:50.685
200 listen:hello world!___8 time:11:25:50.708
20 listen:hello world!___9 time:11:25:50.708
20 listen:hello world!___10 time:11:25:50.745
20 listen:hello world!___11 time:11:25:50.774
20 listen:hello world!___12 time:11:25:50.814
20 listen:hello world!___13 time:11:25:50.859
20 listen:hello world!___14 time:11:25:50.890
20 listen:hello world!___15 time:11:25:50.922
200 listen:hello world!___16 time:11:25:50.922
20 listen:hello world!___17 time:11:25:50.945
20 listen:hello world!___18 time:11:25:50.970
20 listen:hello world!___19 time:11:25:51.001
20 listen:hello world!___20 time:11:25:51.035
20 listen:hello world!___21 time:11:25:51.072
20 listen:hello world!___22 time:11:25:51.100
20 listen:hello world!___23 time:11:25:51.135
200 listen:hello world!___24 time:11:25:51.135
20 listen:hello world!___25 time:11:25:51.167
20 listen:hello world!___26 time:11:25:51.198
20 listen:hello world!___27 time:11:25:51.229
20 listen:hello world!___28 time:11:25:51.267
20 listen:hello world!___29 time:11:25:51.298
20 listen:hello world!___30 time:11:25:51.330
200 listen:hello world!___31 time:11:25:51.347
20 listen:hello world!___32 time:11:25:51.376
20 listen:hello world!___33 time:11:25:51.405
20 listen:hello world!___34 time:11:25:51.433
20 listen:hello world!___35 time:11:25:51.459
20 listen:hello world!___36 time:11:25:51.491
20 listen:hello world!___37 time:11:25:51.521
200 listen:hello world!___39 time:11:25:51.553
20 listen:hello world!___38 time:11:25:51.553
20 listen:hello world!___40 time:11:25:51.588
20 listen:hello world!___41 time:11:25:51.620
20 listen:hello world!___42 time:11:25:51.647
20 listen:hello world!___43 time:11:25:51.702
20 listen:hello world!___44 time:11:25:51.725
20 listen:hello world!___45 time:11:25:51.756
200 listen:hello world!___46 time:11:25:51.756
20 listen:hello world!___47 time:11:25:51.789
20 listen:hello world!___48 time:11:25:51.810
20 listen:hello world!___49 time:11:25:51.846

总时长接近1秒执行完了,消费者2也仅仅消费了7条消息。可能有些同学会疑问,怎么还是大于了1秒呢?不是应该在1秒内执行完吗?消费者1每秒能处理50条,但他才消费了33条就大于1秒了!这锅消费者1不背哈,这个是Thread.sleep()的锅,sleep()完并不一定马上就能执行的,只是进入了就绪态,不是执行态,他还要等cpu的调度。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Spring Cloud实战】Spring Cloud Alibaba Sentinel熔断与限流 (最全讲解,附源码)

gitee地址&#xff1a;https://gitee.com/javaxiaobear/spring-cloud_study.git 在线阅读地址&#xff1a;https://javaxiaobear.gitee.io/ 1、简介 Sentinel 是面向分布式服务架构的流量控制组件&#xff0c;主要以流量为切入点&#xff0c;从流量控制、熔断降级、系统自适应保…

【车载开发系列】CAN总线知识入门篇

【车载开发系列】CAN总线知识入门篇 【车载开发系列】CAN总线知识入门篇【车载开发系列】CAN总线知识入门篇一.总线是什么二.CAN总线是什么三.CAN总线的传输介质四.CAN协议的特性有哪些五.CAN出现的背景六.CAN通信总线的作用七.CAN协议柔软性体现在哪里八.CAN总线的仲裁机制九.…

11月24日:fastadmin根目录下其他文件

addons下的两个文件 其一&#xff1a;.gitkeep 其二&#xff1a;.htaccess application中的common文件 pubilc文件中的uploads runtime中的文件解析 vendor和composer.json的关系 根目录下.gitgnore中的相关标准 composer.json和composer.lock之间的关系 主要是承接之前的fast…

面向对象之抽象类的认识 - (java语法)

文章目录前言1. 什么是抽象类1.1 抽象类与普通类的不同&#xff1a;1.2 子类继承抽象类总结✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来&#xff01; 编程真是一件很奇妙的东西。你只是浅尝辄止&#xff0c;那么只会觉得枯燥乏味&#xff0c;像对待任务似的应付它…

基于JSP的民宿酒店预约管理系统【数据库设计、源码、开题报告】

数据库脚本下载地址&#xff1a; https://download.csdn.net/download/itrjxxs_com/86466879 主要使用技术 SpringStruts2HibernateJSPCSSJSMysql 功能介绍 后台管理&#xff1a; 修改密码&#xff1a;修改个人密码&#xff1b; 会员信息管理&#xff1a;查看会员基本信息并…

C# 学习之路(C# 编程概述)

C# 学习之路&#xff08;C# 编程概述&#xff09; 前记&#xff1a;C# 学习之路&#xff0c;是我跟着 C# 图解教程(第五版) 学习的笔记&#xff0c;每一章都会有一篇笔记发出&#xff0c;小标题会对应书本的章节标题。 .NET 6 和之前的版本相比在顶级语句方面有很大的变化&…

【内网渗透】记一次靶机实战

一、信息收集 1.端口扫描 使用nmap进行端口扫描&#xff0c;发现其开放了22、80、8080、9000端口。 访问其8080端口&#xff0c;发现是一个web界面。 浏览页面内容&#xff0c;提升有一些提示。 【一一帮助安全学习&#xff0c;所有资源获取处一一】 ①网络安全学习路线…

vue2升级vue3的新变化

目录1、组合式API和setup语法糖definePropsdefineEmitsdefineExpose其他2、响应式原理ref和reactiverefreactivetoReftoRefs3、computed和watchcomputedwatchwatchEffect4、v-modelv-model参数v-model修饰符5、key6、v-if和v-for的优先级对比7、异步组件vue 作者&#xff08;尤…

天宇优配|医药股反弹受阻 公募乐观态度不改

历经前期继续反弹后&#xff0c;医药板块11月23日呈现大幅回调&#xff0c;相关细分赛道指数均有所下行&#xff0c;跌幅超越9%的相关个股更是不在少数。 国庆以来这轮医药反弹行情是否就此结束&#xff1f;对此&#xff0c;公募最新预判指出&#xff0c;23日医药板块回调与商场…

mp4视频格式转换器工具,万兴优转-多功能视音频处理软件

MP4是一种大众熟知的视频格式其优势在于在所有的播放器上都能够基本适用因此对于一些较为特殊的视频格式往往都需要将其转换为MP4视频格式才能够在播放器上正常播放。 那么怎样才能将这些特殊的视频格式转换为常用的mp4视频格式呢&#xff1f;这就需要用到mp4视频格式转换器工具…

用于useradd创建用户的规则文件-尚文网络xUP楠哥

~~全文共1026字&#xff0c;阅读需约5分钟。 进Q群11372462&#xff0c;领取专属报名福利&#xff0c;包含云计算学习路线图代表性实战训练大厂云计算面试题资料! # Linux创建普通用户 找来一台Linux系统&#xff0c;首先&#xff0c;执行useradd命令&#xff0c;不加任何参数…

力扣(LeetCode)65. 有效数字(C++)

模拟 面向测试用例的编程&#xff0c;想象到了工程开发的画面。改需求&#xff0c;代码也可以精简&#xff01; 首先判断首位正负号&#xff0c;去除正负号&#xff0c;如果只有一个正负号字符&#xff0c;false。 判断 ′.′.′.′ &#xff0c;如果是单独的 ′.′.′.′ &a…

PS软件下载安装以基本配置

先访问地址 PS下载地址 下载需要付费 给你的下载地址链接一定要保存好 然后根据自己的电脑系统和配置选择一个适合自己的 最后 会下下来一个解压包 然后 我们在 一个盘下 注意 不要用C盘 这里我选择D盘 创建一个文件夹 叫PS设计工具 然后将解压包解压到对应的 PS开发工具文…

第五章 神经网络(下)

5.3 误差逆传播算法 多层网络地学习能力比单层感知机强的多。欲训练多层网络&#xff0c;之前的简单感知机学习规则显然不够用了&#xff0c;需要更强大的学习算法。误差逆传播&#xff08;error BackPropagation&#xff0c;简称BP&#xff09;算法就是其中最杰出的代表。现实…

CPU受限直接执行

目录 1. 虚拟化CPU 2. 进程 2.1 进程的机器状态 2.2 进程创建 2.3 进程的状态 3. 受限直接执行 3.1 直接执行 3.2 受限制的操作 3.3 在进程之间切换 3.3.1 协作方式&#xff1a;等待系统调用 3.3.2 非协作方式&#xff1a;操作系统进行控制 3.3.3 保存和恢复上下…

油藏生产业务+机器学习代理优化算法

前前处理&#xff0c;把后台需要的参数都读出来。写进name.txt 生成新的sch文件&#xff0c;需要在data里追加新sch名字 没改变的井就不用重新卸载关键字里了。 重启动模型&#xff1a;制作出来是空的&#xff0c;得自己加别的东西 模型要准确&#xff0c;否则不好和历史模型…

【吴恩达机器学习笔记】二、单变量线性回归

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为学习吴恩达机器学习视频的同学提供的随堂笔记。 &#x1f4da;专栏简介&#xff1a;在这个专栏&#xff0c;我将整理吴恩达机器学习视频的所有内容的笔记&…

OpenGL原理与实践——核心模式(三):Texture-纹理系统理论与应用

目录 初识——纹理系统是什么&#xff1f;怎么用? Texture —— UV坐标系统 Texture Wrapping&#xff1a;UV超过了[0,1]怎么办&#xff1f; Texture Filter&#xff1a;UV经过计算得到的是浮点数怎么办&#xff1f; 在OpenGL中该怎么做呢&#xff1f; Texture Unit——…

列表和标签企业报告版的完整报告解决方案

列表和标签企业报告版的完整报告解决方案 无缝集成到所有主要开发环境和编程语言&#xff1a;Visual Studio、.NET/。NET核心(C#、VB.NET)、C/C、Delphi/VCL、Java、Progress、DataFlex、dBASE PLUS、Xbase等。 通过现代数据绑定灵活连接到任何数据源&#xff1a;List&Labe…

自适应点云配准(RANSAC、ICP)

点云配准 实验目标 任务一&#xff1a;将两个形状、大小相同的点云进行配准&#xff0c;进而估计两个点云之间的位姿。 任务二&#xff1a;将一些列深度图反向投影得到点云&#xff0c;经过配准后&#xff0c;得到每个深度图之间的位姿变换&#xff0c;并将相应的点云融合到一…