RabbitMQ 工作队列(轮询和公平)
简单队列的缺点:消费者(Consumer)的消费能力有高有低,当生产者(producer)生产能力远远大于消费者能力,那么消息队列消息就会堆积,最终使消息队列达到上限。
引入工作队列,工作队列包括:轮询和公平两种方式。
★工作队列_轮询
轮询就是增加消费者,每个消费者依次读取消息。
1.创建一个Send.java:
package com.ckfuture.work.rr.send; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.nio.charset.StandardCharsets; /** * 工作队列-轮询-消息生产者 */ public class Send { //定义队列名称 private final static String QUEUE_NAME = "work_rr"; public static void main(String[] argv) throws Exception { //创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); //连接工厂的地址 factory.setHost("localhost"); try ( //连接工厂创建连接 Connection connection = factory.newConnection(); //创建信道 Channel channel = connection.createChannel()) { //绑定队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); for (int i = 0; i < 20; i++) { String message = "Hello World!"+i; //发送消息 channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8)); System.out.println(" [x] Sent '" + message + "'"+i); } } } }
2.创建一个Recv01.java:
package com.ckfuture.work.rr.recv; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DeliverCallback; /** * 工作队列-轮询-消息消费者 */ public class Recv01 { private final static String QUEUE_NAME = "work_rr"; public static void main(String[] argv) throws Exception { //创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); //连接工厂创建连接 Connection connection = factory.newConnection(); //创建信道 Channel channel = connection.createChannel(); //绑定队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); DeliverCallback deliverCallback = (consumerTag, delivery) -> { //模拟消费耗时 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } String message = new String(delivery.getBody(), "UTF-8"); System.out.println(" [x] Received '" + message + "'"); /** * 手动确认 * multiple:是否确认多条 */ channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); }; channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { }); } }
3.创建一个Recv02.java:
package com.ckfuture.work.rr.recv; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DeliverCallback; /** * 工作队列-轮询-消息消费者 */ public class Recv02 { private final static String QUEUE_NAME = "work_rr"; public static void main(String[] argv) throws Exception { //创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); //连接工厂创建连接 Connection connection = factory.newConnection(); //创建信道 Channel channel = connection.createChannel(); //绑定队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); DeliverCallback deliverCallback = (consumerTag, delivery) -> { //模拟消费耗时 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } String message = new String(delivery.getBody(), "UTF-8"); System.out.println(" [x] Received '" + message + "'"); /** * 手动确认 * multiple:是否确认多条 */ channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); }; channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { }); } }
4.依次运行Recv01和Recv02
5.在管理控制台查看:
6. 运行Send.java程序
7.可以看到消费者02接收的消息为:
★工作队列_公平
解决消费者之间消费能力差别的问题,按消费能力分配,能者多劳!!即:利用限流控制只有消费完成才允许获取。
限流代码:
//限制消费者每次只能接受一条消息,处理完才能接受下一条消息 int prefetchCount=1; channel.basicQos(prefetchCount);
1.创建一个Send.java
package com.ckfuture.work.fair.send; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.nio.charset.StandardCharsets; /** * 工作队列-公平-消息生产者 */ public class Send { //定义队列名称 private final static String QUEUE_NAME = "work_fair"; public static void main(String[] argv) throws Exception { //创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); //连接工厂的地址 factory.setHost("localhost"); try ( //连接工厂创建连接 Connection connection = factory.newConnection(); //创建信道 Channel channel = connection.createChannel()) { //绑定队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); for (int i = 0; i < 20; i++) { String message = "Hello World!"+i; //发送消息 channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8)); System.out.println(" [x] Sent '" + message + "'"+i); } } } }
2.创建Recv01.java:
package com.ckfuture.work.fair.recv; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DeliverCallback; /** * 工作队列-公平-消息消费者 */ public class Recv01 { private final static String QUEUE_NAME = "work_fair"; public static void main(String[] argv) throws Exception { //创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); //连接工厂创建连接 Connection connection = factory.newConnection(); //创建信道 Channel channel = connection.createChannel(); //绑定队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); //限制消费者每次只能接受一条消息,处理完才能接受下一条消息 int prefetchCount=1; channel.basicQos(prefetchCount); DeliverCallback deliverCallback = (consumerTag, delivery) -> { //模拟消费耗时 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String message = new String(delivery.getBody(), "UTF-8"); System.out.println(" [x] Received '" + message + "'"); /** * 手动确认 * multiple:是否确认多条 */ channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); }; channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { }); } }
公平模式主要设置:
3.创建Recv02.java
package com.ckfuture.work.fair.recv; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DeliverCallback; /** * 工作队列-公平-消息消费者 */ public class Recv02 { private final static String QUEUE_NAME = "work_fair"; public static void main(String[] argv) throws Exception { //创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); //连接工厂创建连接 Connection connection = factory.newConnection(); //创建信道 Channel channel = connection.createChannel(); //绑定队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); //限制消费者每次只能接受一条消息,处理完才能接受下一条消息 int prefetchCount=1; channel.basicQos(prefetchCount); DeliverCallback deliverCallback = (consumerTag, delivery) -> { //模拟消费耗时 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } String message = new String(delivery.getBody(), "UTF-8"); System.out.println(" [x] Received '" + message + "'"); /** * 手动确认 * multiple:是否确认多条 */ channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); }; channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { }); } }
4.依次运行Recv01、Recv02、Send三个程序
Recv01消费能力强消费的多
Recv02消费能力弱
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!