RabbitMQ:预取消息的介绍和使用

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仅支持句柄级别的预拉取数量,不能使用连接数量控制预拉取

分析发现:

  1. 这个所谓的预拉取消息实际上就是限定不确认的消息的数量(即出现指定数量的不确认消息则不再向该消息消费者发送消息)
  2. 该预拉取消息需要开启autoAck=false
  3. 需要使用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控制台结果
RabbitMQ:预取消息的介绍和使用_第1张图片
消费者2控制台结果
RabbitMQ:预取消息的介绍和使用_第2张图片
ui界面结果
RabbitMQ:预取消息的介绍和使用_第3张图片
发现出现了7个消息未确认的结果

4.启动消费者3查看结果
RabbitMQ:预取消息的介绍和使用_第4张图片
消费者3直接消费后面的3条数据

5.关闭消费者1、消费者2再次查看消费者3的结果

消费者3结果
RabbitMQ:预取消息的介绍和使用_第5张图片

ui界面
RabbitMQ:预取消息的介绍和使用_第6张图片

4.总结

1.所谓的预取消息其实就是消息容错限定(当出现指定数量的消息不确认就再次发送了)

2.主要使用的是在消费者端使用的,消费者端需要设定autoAck=false,和basicQos(值)方式开启

以上纯属个人见解,如有问题请联系本人!

你可能感兴趣的:(消息队列)