1.声明
当前内容用于本人学习和复习之用,当前内容主要包括预取消息的介绍和使用,以及其中的坑
当前内容来源:RabbitMQ消息预取和消费者预取
2.官方的Prefetching Messages介绍
For cases when multiple consumers share a queue, it is useful to be able to specify how many messages each consumer can be sent at once before sending the next acknowledgement. This can be used as a simple load balancing technique or to improve throughput if messages tend to be published in batches. For example, if a producing application sends messages every minute because of the nature of the work it is doing.
Note that RabbitMQ only supports channel-level prefetch-count, not connection or size based prefetching.
对于多个消费者共享一个队列的情况,对于可以指定每一个消费者不确认的消息数量是很有用的
,如果消息是被批量推送的方式,这个方式可以实现负载均衡效果。举个例子,如果一个生产者程序通过工作方式每分钟发送消息
注意:RabbitMQ仅支持句柄级别的预拉取数量,不能使用连接数量控制预拉取
分析发现:
- 这个所谓的预拉取消息实际上就是限定不确认的消息的数量(即出现指定数量的不确认消息则不再向该消息消费者发送消息)
- 该预拉取消息需要开启autoAck=false
- 需要使用basciAck进行确认消息
查看如何使用限定:官方限定
发现了这个channel.basicQos(10); //每个使用者限制
3.测试使用预取消息模式
1.创建消费者1(限定未确认消息条数5条)、消费者2(限定未确认消息条数2条)、消费者3(可以正常消费)
消费者1
/**
* @description 当前内容用于测试,多个消费者共享一个消息队列的时候,控制每个消费者获取的消息数量(类似限定消费?)
* @author hy
* @date 2020-05-15
*/
public class PrefetchingMessagesTest {
private static final int prefetchCount=5;
public static void main(String[] args) throws Exception {
RabbitMqUtils mqUtils = new RabbitMqUtils();
Connection connection = mqUtils.getConnection();
Channel channel = connection.createChannel();
channel.basicQos(prefetchCount);
System.out.println("如果出现[" + prefetchCount + "] 条消息未处理,则出现不再接收任何消息处理的情况====>");
// 开启自动确认
channel.basicConsume("hello", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
throws IOException {
// 限定消费的条数
System.out.println("消费者2开始处理消息====>" + new String(body, "utf-8"));
System.out.println(consumerTag);
System.out.println(envelope.getDeliveryTag());
// channel.basicAck(envelope.getDeliveryTag(), false);
// 这里也不确认
}
});
}
}
消费者2
/**
* @description 当前内容用于测试,多个消费者共享一个消息队列的时候,控制每个消费者获取的消息数量(类似限定消费?)
* @author hy
* @date 2020-05-15
*/
public class PrefetchingMessages2Test {
private static final int prefetchCount = 2;
public static void main(String[] args) throws Exception {
RabbitMqUtils mqUtils = new RabbitMqUtils();
Connection connection = mqUtils.getConnection();
Channel channel = connection.createChannel();
channel.basicQos(2);
System.out.println("如果出现[" + prefetchCount + "] 条消息未处理,则出现不再接收任何消息处理的情况====>");
// 开启自动确认
channel.basicConsume("hello", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
throws IOException {
System.out.println("消费者1开始处理消息====>" + new String(body, "utf-8"));
System.out.println(consumerTag);
System.out.println(envelope.getDeliveryTag());
// channel.basicAck(envelope.getDeliveryTag(), false);
// 直接不确认,分析发现qos作用
}
});
}
}
消费者3
/**
* @description 当前内容用于测试,多个消费者共享一个消息队列的时候,控制每个消费者获取的消息数量(类似限定消费?)(实际消费者)
* @author hy
* @date 2020-05-15
*/
public class PrefetchingMessages3Test {
public static void main(String[] args) throws Exception {
RabbitMqUtils mqUtils = new RabbitMqUtils();
Connection connection = mqUtils.getConnection();
Channel channel = connection.createChannel();
// 开启自动确认
channel.basicConsume("hello", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
throws IOException {
// 限定消费的条数
System.out.println("消费者3开始处理消息====>" + new String(body, "utf-8"));
channel.basicAck(envelope.getDeliveryTag(), false);
}
});
}
}
2.创建消息生产者
public class MessageSenderApplication {
@Test
public void testSender() throws Exception {
RabbitMqUtils mqUtils = new RabbitMqUtils();
for (int i = 0; i < 10; i++) {
mqUtils.send("test", "", true, null, "你好,世界!" + (i));
}
}
}
3.启动消费者1、消费者2、消息生产者并观察结果
消费者1控制台结果
消费者2控制台结果
ui界面结果
发现出现了7个消息未确认的结果
4.启动消费者3查看结果
消费者3直接消费后面的3条数据
5.关闭消费者1、消费者2再次查看消费者3的结果
消费者3结果
ui界面
4.总结
1.所谓的预取消息其实就是消息容错限定(当出现指定数量的消息不确认就再次发送了)
2.主要使用的是在消费者端使用的,消费者端需要设定autoAck=false,和basicQos(值)方式开启
以上纯属个人见解,如有问题请联系本人!