RabbitMQ 之 Work queues
一、概述
Work queues 该模式下有一个生产者(Producer)、两个消费者(Consumer01、Consumer02),多个消费者一起处理生产者发送过来的消息,消息分发给消费者一般有两种方式,分别是轮询分发(公平分发)、预期值分发(不公平分发)
轮询分发是默认的分发方式,对应的是 prefetchCount = 0,它采用的是公平分发的方式,消息分发与消费者的消费速度没有任何关系,如果 prefetchCount != 0,那么它就采用不公平的分发方式,即先按照预期值分发,分发完成之后再按照消费者的消费速度进行消息分发
二、轮询分发(默认值)
默认情况下,工作队列(Work queues)采用的是轮询分发的策略,与具体的消费者处理速度快慢没有任何关系
1、工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class RabbitmqUtils { private static final String HOST_ADDRESS = "192.168.59.130" ; private static final String USER_NAME = "admin" ; private static final String PASSWORD = "admin123" ; public static Channel getChannel() throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost(HOST_ADDRESS); factory.setUsername(USER_NAME); factory.setPassword(PASSWORD); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); return channel; } } |
2、Producer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class Producer { private static final String QUEUE_NAME = "WorkQueuesDemo" ; public static void main(String[] args) throws Exception { Channel channel = RabbitmqUtils.getChannel(); channel.queueDeclare(QUEUE_NAME, true , false , false , null ); String message = "有意思的消息--->" ; for ( int i = 1 ; i < 11 ; i++) { channel.basicPublish( "" , QUEUE_NAME, null , (message + i).getBytes(StandardCharsets.UTF_8)); } System.out.println( "Producer send message successfully" ); } } |
3、Consumer01
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class Consumer01 { private static final String QUEUE_NAME = "WorkQueuesDemo" ; public static void main(String[] args) throws Exception { Channel channel = RabbitmqUtils.getChannel(); channel.queueDeclare(QUEUE_NAME, true , false , false , null ); DeliverCallback deliverCallback = (consumerTag, delivery) -> { String message = new String(delivery.getBody()); // 休眠 10 s try { Thread.sleep( 10 * 1000 ); } catch (InterruptedException e) { e.printStackTrace(); } // 参数一、deliveryTag:消息应答标记 // 参数二、multiple:(false、只应答接收到的那个消息 true、应答所有传递过来的消息) // 处理完逻辑之后应答 ack channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false ); System.out.println(message); }; // prefetchCount 的默认值为 0 // 不设置 basicQos 与 channel.basicQos(0) 的效果是等价的,即采用轮询分发的策略 channel.basicQos( 0 ); // 设置手动应答 boolean autoAck = false ; channel.basicConsume(QUEUE_NAME, autoAck, deliverCallback, (consumerTag) -> { System.out.println(consumerTag); }); } } |
4、Consumer02
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class Consumer02 { private static final String QUEUE_NAME = "WorkQueuesDemo" ; public static void main(String[] args) throws Exception { Channel channel = RabbitmqUtils.getChannel(); channel.queueDeclare(QUEUE_NAME, true , false , false , null ); DeliverCallback deliverCallback = (consumerTag, delivery) -> { String message = new String(delivery.getBody()); // 参数一、deliveryTag:消息应答标记 // 参数二、multiple:(false、只应答接收到的那个消息 true、应答所有传递过来的消息) // 处理完逻辑之后应答 ack channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false ); System.out.println(message); }; // 设置 prefetchCount channel.basicQos( 0 ); // 设置手动应答 boolean autoAck = false ; channel.basicConsume(QUEUE_NAME, autoAck, deliverCallback, (consumerTag) -> { System.out.println(consumerTag); }); } } |
5、测试过程及结果
首先启动 Cousumer01、Consumer02,然后设置 prefetchCount = 0,接着启动 Producer 发送消息,切换到 RabbitMQ 控制台
6、Consumer01、Consumer02 的消费情况
三、不公平分发(预期值分发1)
代码和上面的基本相同,只是将 Consumer01、Consumer02 的 prefetchCount 设置为 1 即可,消息的分发会取决于消费者的处理速度,性能好的消费者将分发到更多的消息
1、原理图
2、RabbitMQ 控制台
3、Consumer01、Consumer02 的消费情况
Consumer01、Consumer02 先按照 prefetchCount = 1(预期值)进行分发,然后剩下的消息按照消费者的性能进行分配
四、不公平分发(预期值分发2)
代码和上面的基本相同,只是将 Consumer01 的 prefetchCount 设置为 2、Consumer02 的 prefetchCount 设置为 4 即可
1、原理图
2、RabbitMQ 控制台
3、Consumer01、Consumer02 的消费情况
Consumer01 设置了 prefetchCount = 2,Consumer02 设置了 prefetchCount = 4,所以 10 个消息分发两个给 Consumer01,分发 4 个给 Consumer02,剩下的 4 个消息的分发取决于消费者的处理速度(目前测试)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?