死信队列、延迟队列、消息的幂等性消费
一、通过代码实现创建队列和交换机以及绑定
- application.yml
# 端口号
server:
port: 8083
# rabbitmq配置
spring:
rabbitmq:
host: 192.168.31.129
- 代码实现
package com.hong.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author hongCheng
* @Date 2021/4/22 18:58
* @Version 1.0
*/
@Configuration
public class RabbitConfig {
private final String QUEUE = "myqueue03";//定义一个队列的名字
private final String EXCHANGE = "myexchange03";//定义一个交换机的名字
/**
* 创建交换机
* directExchange 路由交换机模式
* durable 是否持久化
* @return
*/
@Bean
public Exchange exchange(){
return ExchangeBuilder.directExchange(EXCHANGE).durable(true).build();
}
/**
* 创建队列
* durable 队列的名字
* withArgument(key,value):
* key:参数的名字
* value:参数的值
* @return
*/
@Bean
public Queue queue(){
return QueueBuilder.durable(QUEUE).withArgument("x-message-ttl",20000).build();
}
/**
* 绑定
* bind(queue()).to(exchange()) 将队列绑定到交换机上
* with("") 如果没有路由,可以不写
* noargs() 无参
* @return
*/
@Bean
public Binding binding(){
return BindingBuilder.bind(queue()).to(exchange()).with("").noargs();
}
}
- 结果
二、死信队列
死信队列,英文缩写:DLX Dead Letter Exchange(死信交换机),当消息称为Dead message后,可以被重新发送到另一个交换机,这个交换机就是DLX。
消息称为死信的三种情况:
1.队列消息长度到达限制;
2.消费者拒接消息,basicNack/basicReject,并且不将消息重新放入到原目标队列,requeue=false;
3.原队列存在消息过期设置,消息到达超时时间违背消费。
队列绑定死信交换机
给队列设置参数:x-dead-letter-exchange和x-dead-letter-routing-key
代码实现:
package com.hong.product;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author hongCheng
* @Date 2021/4/22 15:42
* @Version 1.0
*/
@Configuration
public class ProductConfig {
private final String QUEUE = "myqueue03";
private final String DEAD_QUEUE = "dead_queue";
private final String EXCHANGE = "exchange";
private final String DEAD_EXCHANGE = "dead_exchange";
/**
* 创建队列
* durable 队列的名字
* withArgument(key,value)
* key 参数的名字
* value 参数的值
* @return
*/
@Bean
public Queue queue(){
return QueueBuilder.durable(QUEUE)
.withArgument("x-message-ttl",30000)//设置参数的超时时间
.withArgument("x-max-length",20)//参数的最多数量
.withArgument("x-dead-letter-exchange",DEAD_EXCHANGE)//与死信交换机绑定关系
.withArgument("x-dead-letter-routing-key","error")//设置路由
.build();
}
/**
* 创建死信队列
* @return
*/
@Bean
public Queue dead_queue(){
return QueueBuilder.durable(DEAD_QUEUE).build();
}
/**
* 创建交换机
* @return
*/
@Bean
public Exchange exchange(){
return ExchangeBuilder.directExchange(EXCHANGE).build();
}
/**
* 创建死信交换机
* @return
*/
@Bean
public Exchange dead_exchange(){
return ExchangeBuilder.directExchange(DEAD_EXCHANGE).build();
}
/**
* 将普通交换机跟普通队列绑定
* @return
*/
@Bean
public Binding binding(){
return BindingBuilder.bind(queue()).to(exchange()).with("error").noargs();
}
/**
* 将死信队列与死信交换机绑定
* @return
*/
@Bean
public Binding dead_binding(){
return BindingBuilder.bind(dead_queue()).to(dead_exchange()).with("error").noargs();
}
}
在测试类中写一个类显示结果;
package com.hong;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @Author hongCheng
* @Date 2021/4/22 20:13
* @Version 1.0
*/
@SpringBootTest
public class ProduceTest {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 测试死信队列
*/
@Test
public void testDeadExchange(){
/**
* String exchange, 交换机名字
* String routingKey, 路由密钥
* final Object object 信息
*/
rabbitTemplate.convertAndSend("exchange","error","多喝热水");
}
}
结果显示:
20秒后,时间达到之后进入到死信队列:
三、延迟队列
延迟队列:就是消息进入队列后不会立即被消费,只有达到指定事件后,才会被消费
实现方式:
- 定时器
- 延迟队列
在rabbitmq中并未提供延迟队列的功能
可以使用TTL+死信队列
组和实现延迟队列的效果
将延迟队列设置过期时间30分钟,就比如订单,如果你没有支付订单,订单会给你保留一定的时间,时间一到就会自动默认为取消订单。
四、消息幂等性保障
幂等性指一次性和多次请求某一个资源,对于资源本身应该具有同样的结果。也就是说,其任意多次执行对资源本身所产生的影响均与依次执行的影响相同。
可以保证消息不被重复消费
- 消费者获取到信息后先根据id(唯一标识)去查询redis/db中是否存在该消息
- 如果不存在,则正常消费,消费完毕后写入redis/db中
- 如果存在,则证明消息被消费过,直接丢弃。