在rabbitmq中不存在延时队列,但是我们可以通过设置消息的过期时间和死信队列来模拟出延时队列。消费者监听死信交换器绑定的队列,而不要监听消息发送的队列。
消息会进入死信队列的情况:
- 消息被拒绝(Basic.Reject或Basic.Nack)并且设置 requeue 参数的值为 false
- 消息过期了
- 队列达到最大的长度
我们使用第二种方式实现延时队列
如何设置过期时间:
在 rabbitmq 中存在2种方可设置消息的过期时间,第一种通过对队列进行设置,这种设置后,该队列中所有的消息都存在相同的过期时间,第二种通过对消息本身进行设置,那么每条消息的过期时间都不一样。如果同时使用这2种方法,那么以过期时间小的那个数值为准。当消息达到过期时间还没有被消费,那么那个消息就成为了一个 死信 消息。
队列设置:在队列申明的时候使用 x-message-ttl 参数,单位为 毫秒
单个消息设置:是设置消息属性的 expiration 参数的值,单位为 毫秒
配置
spring:
cloud:
stream:
#RabbitMQ服务器地址配置
binders:
windrabbit:
type: rabbit
environment:
spring:
rabbitmq:
addresses: localhost
port: 15672
username: guest
password: guest
default:
consumer:
maxAttempts: 1 #默认为3次,禁用重试
bindings:
delay-output:
destination: delay.exchange #交换机
binder: windrabbit #指定mq配置
content-type: application/json
group: delay-order
producer:
requiredGroups: delay-order #没有消费者时声明这个才会创建队列
#delay-input:
#destination: delay.exchange
#binder: windrabbit
#content-type: application/json
#group: delay-order
#这一部分是给上边声明的bindings添加配置的,例如队列的ttl,还有要不要给队列配置死信队列
rabbit:
bindings:
delay-output:
producer:
ttl: 120000#队列里的消息如果120000ms之后还没被消费,就会成为死信,这个参数生效的前提是spring.cloud.stream.bindings里边声明了requiredGroups
autoBindDlq: true#这个参数为true的时候会自动为当前的队列创建一个死信队列,以dlq结尾
新建一个Processor来映射上边配置的bindings
public interface MQOrderProcessor {
// 不需要映射消息队列
// String DELAYINPUT="delay-input";
// @Input(MQOrderProcessor.DELAYINPUT)
// SubscribableChannel delayOrderInput();
String DELAYOUTPUT="delay-output";
@Output(MQOrderProcessor.DELAYOUTPUT)
MessageChannel delayOrderOutput();
}
@Output对MessageChannel,@Input对应SubscribableChannel,不少人用错,注意不要混用
(1)MessageChannel
MessageChannel 是Spring Integration消息通道的顶级接口:
在该接口中,没有提供从channel中接收消息的方法,这个是因为spring integration的channel有两个不同的机制来处理接收消息,polling 、subscription,分别有两个子接口来表示。
(2)PollableChannel
PollableChannel 具备轮询获得消息的能力,这种channel要求消息消费者或者框架去周期性的检查是否有可用的消息到达
(3)SubscribableChannel
SubscribableChannel 发送消息给订阅了MessageHanlder的订阅者
发送消息的代码
@AllArgsConstructor
@EnableBinding(MQOrderProcessor.class)
public class OrderMessageProvider {
private MQOrderProcessor processor;
public boolean sendCancelOrderMessage(){
System.out.println("start send message to mq");
return processor.delayOrderOutput().send(MessageBuilder.withPayload("{message:'cancel order'}").build());
}
}
接收死信队列消息
@RabbitListener(queues = "debug")
public void processMessage1(@Payload String body, @Header String token) {
System.out.println("body:"+body);
System.out.println("token:"+token);
}
这里也可以使用@StreamListener,自动转换对象和json
延迟消息使用场景
1. 订单超时失效。这种功能具有零散性,使用mq比使用定时任务更灵活、高效。
本文介绍了如何在RabbitMQ中通过设置消息过期时间和死信队列来模拟延迟队列。详细讲解了消息过期的两种设置方式,并提供了Spring Cloud Stream的配置方法,包括MessageChannel和SubscribableChannel的使用。最后讨论了延迟消息在订单超时失效等场景的应用。
271

被折叠的 条评论
为什么被折叠?



