1. rabbitMQ的推模式和拉模式
我们知道,消费者有两种方式从消息中间件获取消息:
推模式:消息中间件主动将消息推送
给消费者
拉模式:消费者主动从消息中间件拉取
消息
推模式:将消息提前推送给消费者,消费者必须设置一个缓冲区缓存这些消息。好处很明显,消费者总是有一堆在内存中待处理的消息,所以效率高。缺点:是缓冲区可能会溢出。
实现推模式:推荐的方式是继承DefaultConsumer
基类,也可以使用Spring AMQP
的SimpleMessageListenerContainer
。
拉模式:在消费者需要时才去消息中间件拉取消息,这段网络开销会明显增加消息延迟,降低系统吞吐量。
实现拉模式:RabbitMQ
的Channel
提供了basicGet
方法用于拉取消息。
push
更关注实时性,pull
更关注消费者消费能力
推模式是做最常用的,但是某些情况下推模式并不适用:
- 由于某些限制,消费者在某个条件成立时才能消费消息。
- 需要批量拉取消息进行处理。
1.1 实时拉(pull)模式
With AMQP 0-9-1 it is possible to fetch messages one by one using the basic.get protocol method. Messages are fetched in the FIFO order. It is possible to use automatic or manual acknowledgements, just like with consumers (subscriptions).
Fetching messages one by one is not necessary in most cases as it is inefficient and has all the downsides of polling. When in doubt, prefer registering a consumer.
官方对pull的定义是:可以使用basic.get
协议方法逐个获取消息。消息以FIFO
(先进先出)顺序获取,可以使用手动确定,就像消费者(订阅)一样。
大多数情况下,不需要逐个获取消息。因为它的效率低,并且具有轮询的所有缺点。
使用basicGet
拉模式需要注意:
- Queue中没有消息是basicGet返回null,此时应用应当适当休眠。
- 如果需要实现消息的可靠消费,应当传递autoAck为false。
GetResponse
的envelope
属性的deliveryTag
属性用于ACK消息传递给basicAck
。- 使用拉模式需要自己实现线程池。
1.2. 批量拉取(pull)消息
RabbitMQ支持客户端批量拉取消息,可以连续调用basicGet
方法拉取多条消息,处理完毕一次性返回ACK。
需要注意:
- 批量拉取循环的退出条件:达到数量上限,basicGet返回null。
- 使用basic批量ACK传递的参数是最后一条消息的deliveryTag。
1.3 SpringBoot中使用pull拉取消息
可以通过AmqpTemplate
或者RabbitMqTemplate
拉取消息,当queue没有消息时,会立刻返回null,传入timeoutMillis参数可阻塞等待一段时间。
Message receive() throws AmqpException;
Message receive(String queueName) throws AmqpException;
Message receive(long timeoutMillis) throws AmqpException;
Message receive(String queueName, long timeoutMillis) throws AmqpException;
若是想直接在queue获取到java对象,可以调用receiveAndConvert
方法。
测试代码:
@Test
public void receive() {
Object o = rabbitTemplate.receiveAndConvert("queue_direct");
System.out.println(o.hashCode());
System.out.println(o);
}
SpringBoot2.x处理消息详见:【RabbitMQ-6】消费端获取消息(SpringBoot2.0版本)