rabbitmq死信队列、延迟队列、幂等性保障

死信队列
什么是死信

死信队列,英文缩写DLX。Dead Letter Exchange(死信交换机),当消息成为Dead message(死信信息)后,可以被重新发送到另一个交换机上,这就是DLX
在这里插入图片描述消息成为死信的三种情况

1.队列消息长度到达限制;
2.消费者拒接消费消息,basicNack/basicReject,并且不把消息重新放入原目标队列,requeue=false;
3.原队列存在消息过期设置,消息到达超时时间未被消费;

使用死信

队列绑定死信交换机:

给队列设置参数: x-dead-letter-exchange 和 x-dead-letter-routing-key
在这里插入图片描述在idea中使用配置文件创建
在这里插入图片描述在配置类中编写代码,确保程序启动配置类中的实例对象可以被加载

@Configuration
public class ExchangeAndQueue {
    private final String QUEUE="queue";//普通队列
    private final String DEAD_QUEUE="dead_queue";//死信队列
    private  final String EXCHANGE="exchange";//普通交换机
    private  final String DEAD_EXCHANGE="dead_exchange";//死信交换机

    //java代码创建普通的队列
    @Bean
    public Queue queue(){
        return QueueBuilder
                .durable(QUEUE)//持久化队列(参数为队列名称)
                .withArgument("x-message-ttl",20000)//设置超时时间
                .withArgument("x-max-length",10)//最大个数
                .withArgument("x-dead-letter-exchange",DEAD_EXCHANGE)//设置死信队列
                .withArgument("x-dead-letter-routing-key","error")//设置死信路由key
                .build();//创建
    }

    //创建死信队列
    @Bean
    public Queue dead_queue() {
        /**
         * durable(DEAD_QUEUE)持久化队列(参数为队列名称)
         * build()创建
         */
        return QueueBuilder.durable(DEAD_QUEUE).build();
    }

    //创建普通交换机
    @Bean
    public Exchange exchange(){
        /**
         * directExchange(EXCHANGE)交换机类型(交换机名称)
         * build()创建
         */
        return ExchangeBuilder.directExchange(EXCHANGE).build();
    }

    //创建死信交换机
    @Bean
    public Exchange dead_exchange(){
        /**
         * directExchange(DEAD_EXCHANGE)交换机类型(交换机名称)
         * build()创建
         */
        return  ExchangeBuilder.directExchange(DEAD_EXCHANGE).build();
    }

    //绑定普通队列和普通1交换机
    @Bean
    public Binding binding(){
        /**
         * bind(queue())要绑定的队列对象
         * to(exchange())绑定到的交换机对象
         * with("error")路由key
         * noargs();没有额外参数
         * @return
         */
        return  BindingBuilder.bind(queue()).to(exchange()).with("error").noargs();
    }

    //绑定死信队列和死信交换机
    @Bean
    public Binding dead_binding(){
        /**
         * bind(dead_queue())要绑定的队列对象
         * to(dead_exchange())绑定到的交换机对象
         * with("error")路由key
         * noargs();没有额外参数
         * @return
         */
        return  BindingBuilder.bind(dead_queue()).to(dead_exchange()).with("error").noargs();
    }
}

在可视化web创建
1.创建普通交换机
在这里插入图片描述2.创建死信交换机
在这里插入图片描述3.创建死信队列
在这里插入图片描述4.创建普通队列
在这里插入图片描述5.绑定队列和交换机
在这里插入图片描述挨个绑定普通队列、交换机和死信队列、交换机
在这里插入图片描述延迟队列
在这里插入图片描述普通队列中设置失效时间,当普通队列中的信息超出时间未被消费时,就会进入死信队列中,

案例:超出30分钟未支付就删除订单并且让库存回滚
消息幂等性保障

幂等性: 无论执行多少次,得到的结果和第一次都是相同的。 LOL中的英雄大招技能,在冷却好了到放过等待大招cd过程中,只有一次点击有效。这就是幂等性

防止在消费者进行回应时因为一系列问题未响应给队列,从而不删除此信息,导致再次消费,保证了消息不被重复消费。

实现步骤
这里使用redis完成
在这里插入图片描述1.开启redis
在这里插入图片描述2.引入依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

3.配置application.yml文件

#配置rabbitmq的IP
spring:
  rabbitmq:
    host: 192.168.11.222
    #开启手动确认
    listener:
      simple:
        acknowledge-mode: manual
   #配置redis的端口和IP
  redis:
    host: 192.168.11.222
    port: 6379
server:
  port: 8002

4.代码实现
在配置类中写

@Component
public class MyListener {
	//注入redisTemplate用来操作redis数据库
    @Autowired
    private RedisTemplate redisTemplate;
    //@RabbitListener(queues = "queue")监听rabbitmq的那个队列
    @RabbitListener(queues = "queue")
    /**
    *Message msg 要消费的信息
    *Channel channel 信道对象
    */
    public void listener(Message msg, Channel channel) throws  Exception{
		//先连接redis数据库查看是否有用此信息的唯一标识为key的记录 
        Object o = redisTemplate.opsForValue().get(msg.getMessageProperties().getDeliveryTag());
        //判断是否取到值,取到就说明已经进行过操作,没有就是第一次进行业务代码
        if(o==null){
            //业务代码
            try {
                System.out.println("完成业务功能");
                //完成业务后通过redisTemplate.opsForValue().set方法往redis中存放key为此信息的唯一标识为key的记录 ,方便下次如果在重复操作此信息时进行判断
                redisTemplate.opsForValue().set(msg.getMessageProperties().getDeliveryTag(), "ykq");
                //完成后手动把信息从队列中消费删除掉
                channel.basicAck(msg.getMessageProperties().getDeliveryTag(), true);
            }catch (Exception e){
            //如果出现异常就从队列中删除掉此信息,并且要求生产者重新发送信息到队列中
                channel.basicNack(msg.getMessageProperties().getDeliveryTag(),true,true);
            }
        }else{
        //否则就是重复操作,就直接从队列中删除掉此信息
            channel.basicAck(msg.getMessageProperties().getDeliveryTag(),true);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值