目录
一、TTL
1、什么是TTL
2、设置TTL的两种方式
3、控制台设置TTL
4、SpringBoot实现两种方式设置TTL
1.给消息设置过期时间
2.给队列设置过期时间
二、DLX死信队列
1、什么是死信交换机与死信队列
2、消息何时会成为死信
3、队列如何绑定死信交换机与死信队列
4、SpringBoot实现死信队列
三、延迟队列
1、什么是延迟队列
2、使用场景
四、SpringBoot整合RabbitMQ实现延迟队列案例之订单超时
1、实现思路
2、代码实现
一、TTL
1、什么是TTL
TTL(Time To Live):存活时间/过期时间,在RabbitMQ里表示消息从生产者到服务器后该消息的存活时间,一旦到达时长该消息就会被自动清除
2、设置TTL的两种方式
在RabbitMQ里有两种设置过期时间的方式,分别是给消息单独设置时长、给队列设置过期时长,该队列里所有的消息都是该时长,当两种都设置了时以时间短的为准。消息在队列里到达过期时长并不是马上去删除,如果马上删除需要服务器去无时不刻的扫描或者去做其他算法来检测,导致服务器性能变低,RabbitMQ的做法是当消息到达队顶时判断消息是否过期,如果过期则删除,没过期则给消费者
3、控制台设置TTL
我们打开控制台,在创建队列时如下图
点击此处即可设置时长单位是毫秒,此时发送消息到该队列在设定的过期时间后观察该队列消息数为0,消息由于过期被丢失
4、SpringBoot实现两种方式设置TTL
在实现之前我们需要去创建一个配置类并在里创建队列
关于此处 创建交换机与队列代码在之前文章里有提到
1.给消息设置过期时间
在发送消息时使用该匿名内部类设置过期时间
2.给队列设置过期时间
该种方式只需在配置类创建队列时指定即可
在此处指定时长即可,我们给创建好的队列发送给消息队列收到消息后指定的时间后会将该消息丢弃
二、DLX死信队列
1、什么是死信交换机与死信队列
死信队列英文缩写DLX,Dead Letter Exchange(死信交换机)当消息成为死消息后,可以被重新发送到另一个交换机,这个交换机就是死信交换机,在由该交换机转发给相应的死信队列
2、消息何时会成为死信
那么什么是消息才会变成死信呢,有以下三种情况:队列长度达到最大限制此时收到的消息就是死信或者被消费者拒收且消费者不设置重回队列的消息就是死信以及在原队列超过时间限制的消息
3、队列如何绑定死信交换机与死信队列
正常队列绑定死信交换机后,他的死信就可以由死信交换机转发到死信队列。在创建普通队列时我们需要绑定的有死信交换机与死信队列的路由,此时普通队列就类似生产者,生产者发送消息时需要指定路由此处也相同
4、SpringBoot实现死信队列
在实现死信队列时,我们需要创建正常队列与正常交换机,然后创建死信交换机与死信队列。然后修改创建普通队列的代码绑定死信交换机与死信队列
我们先来创建普通队列与普通交换机并进行绑定以及死信交换机与死信队列
package com.example.demo.delay;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DelayQueueConfig {
// 1.创建正常队列交换机与私信交换机与队列
public static final String NOR_QUEUE = "norQueue"; // 普通队列
public static final String NOR_EXCHANGE = "norEx"; // 普通交换机
public static final String DLX_QUEUE = "dlxQueue"; // 死信队列
public static final String DLX_EXCHANGE = "dlxEx"; // 死信交换机
public static final String DLX_ROUTING_KEY = "dlx"; // 死信队列路由
public static final String NOR_ROUTING_KEY = "nor"; // 普通队列路由
@Bean
public Queue norQueue(){
// 创建普通队里绑定私信交换机与发送到死信队列的路由
return QueueBuilder.durable(NOR_QUEUE).ttl(10000).build();
}
@Bean
public DirectExchange norEx() {
// 创建普通交换机
return ExchangeBuilder.directExchange(NOR_EXCHANGE).build();
}
@Bean
public Binding bindingNor(@Qualifier("norQueue")Queue norQueue,@Qualifier("norEx")DirectExchange norEx) {
// 将普通队里与普通交换机绑定
return BindingBuilder.bind(norQueue).to(norEx).with(NOR_ROUTING_KEY);
}
@Bean
public Queue dlxQueue() {
// 创建死信队列
return QueueBuilder.durable(DLX_QUEUE).build();
}
@Bean
public DirectExchange dlxEx() {
// 创建死信交换机
return ExchangeBuilder.directExchange(DLX_EXCHANGE).build();
}
@Bean
public Binding bindingDLX(@Qualifier("dlxQueue") Queue dlxQueue,@Qualifier("dlxEx")DirectExchange dlxEx) {
// 将死信队列与死信交换机绑定
return BindingBuilder.bind(dlxQueue).to(dlxEx).with(DLX_ROUTING_KEY);
}
}
此时我们需要修改创建普通队列的代码让他与死信交换机进行绑定并设置死信要到达的死信队列的路由
这个时候我们发送一条数据到普通队列,经过指定的时间后变为死信就会进入死信队列,后续可以创建消费者去消费死信队列里的信息
三、延迟队列
1、什么是延迟队列
在RabbitMQ里当消息到达队列后不会立马被消费者消费,而是到达指定的时间才会被消费。
2、使用场景
比如我们可以在用户注册后的第n天给用户发送邮件,或者当用户下单后10分钟以内如果没有被支付就将订单信息回滚
四、SpringBoot整合RabbitMQ实现延迟队列案例之订单超时
1、实现思路
在RabbitMQ里没有提供延迟队列,但是我们发现上述场景类似我们在前面提到的死信队列,我们可以通过TTL+DLX也就是死信队列与设置消息过期时长来实现延迟队列,拿订单超时未支付来举例子,当用户下单后我们将订单信息发个MQ,并设置该订单信息的存活时长为10分钟,10分钟后它就会变为死信进入死信队列,此时我们只需要监听死信队列,然后拿到信息后去数据库查询是否支付,如果没有支付就回滚库存
2、代码实现
我们首先需要创建普通队列、普通交换机、死信队列、死信交换机然后普通队列绑定死信交换机并设置消息存活时长为10分钟,代码与上面实现死信队列类型
package com.example.demo.delay;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DelayQueueConfig {
// 1.创建正常队列交换机与私信交换机与队列
public static final String NOR_QUEUE = "norQueue"; // 普通队列
public static final String NOR_EXCHANGE = "norEx"; // 普通交换机
public static final String DLX_QUEUE = "dlxQueue"; // 死信队列
public static final String DLX_EXCHANGE = "dlxEx"; // 死信交换机
public static final String DLX_ROUTING_KEY = "dlx"; // 死信队列路由
public static final String NOR_ROUTING_KEY = "nor"; // 普通队列路由
@Bean
public Queue norQueue(){
// 创建普通队里绑定私信交换机与发送到死信队列的路由
return QueueBuilder.durable(NOR_QUEUE).ttl(时长).
deadLetterExchange(DLX_EXCHANGE).deadLetterRoutingKey(DLX_ROUTING_KEY).build();
}
@Bean
public DirectExchange norEx() {
// 创建普通交换机
return ExchangeBuilder.directExchange(NOR_EXCHANGE).build();
}
@Bean
public Binding bindingNor(@Qualifier("norQueue")Queue norQueue,@Qualifier("norEx")DirectExchange norEx) {
// 将普通队里与普通交换机绑定
return BindingBuilder.bind(norQueue).to(norEx).with(NOR_ROUTING_KEY);
}
@Bean
public Queue dlxQueue() {
// 创建死信队列
return QueueBuilder.durable(DLX_QUEUE).build();
}
@Bean
public DirectExchange dlxEx() {
// 创建死信交换机
return ExchangeBuilder.directExchange(DLX_EXCHANGE).build();
}
@Bean
public Binding bindingDLX(@Qualifier("dlxQueue") Queue dlxQueue,@Qualifier("dlxEx")DirectExchange dlxEx) {
// 将死信队列与死信交换机绑定
return BindingBuilder.bind(dlxQueue).to(dlxEx).with(DLX_ROUTING_KEY);
}
}
此时在消费者端我们只需要去监听死信队列即可
package com.example.demo.delay;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class Consumer {
@RabbitListener(queues = DelayQueueConfig.DLX_QUEUE)
public void delay(Message message) {
System.out.println("获取到订单," + message.getBody() + "查询数据库是否已支付?未支付则回滚");
}
}