死信队列,让订单超时的时候有更高的可用性

死信队列

关于RabbitMQ死信队列
死信队列 听上去像 消息“死”了 其实也有点这个意思,死信队列 是 当消息在一个队列 因为下列原因:
消息被拒绝(basic.reject/ basic.nack)并且不再重新投递 requeue=false
消息超期过期 (rabbitmq Time-To-Live -> messageProperties.setExpiration())
队列超载:
变成了 “死信” 后 被重新投递(publish)到另一个Exchange 该Exchange 就是DLX 然后该Exchange 根据绑定规则 转发到对应的 队列上 监听该队列 就可以重新消费 说白了 就是 没有被消费的消息 换个地方重新被消费
生产者 --> 消息 --> 交换机 --> 队列 --> 变成死信 --> DLX交换机 -->队列 --> 消费者

一 、队列的创建和绑定

 	public static final String EXCHANGE = "zw.dead.exchange";
    public static final String ROUTING_KEY = "zw.dead.routingKey";
    public static final String NORMAL_QUEUE = "zw.dead.normal.queue";
    public static final String NORMAL_EXCHANGE = "zw.dead.normal.exchange";
    public static final String NORMAL_ROUTING_KEY = "zw.dead.normal.routingKey";
    public static final String REAL_DEAD_QUEUE = "zw.dead.queue";
    public static final int QUEUE_EXPIRE = 6000000;
    public static final int EXPIRE = 30000;

    /**
     * 创建普通交换机
     */
    @Bean
    public Exchange normalExchange() {
        return new TopicExchange(NORMAL_EXCHANGE, true, false);
    }

    /**
     * 绑定普通队列和普通交换机
     */
    @Bean
    public Binding normalBind() {
        return BindingBuilder.bind(normalQueue()).to(normalExchange()).with(NORMAL_ROUTING_KEY).noargs();
    }

    /**
     * 创建死信交换机
     */
    @Bean
    public Exchange deadExchange() {
        return new TopicExchange(EXCHANGE, true, false);
    }

    /**
     * 创建真实存储死信的队列,当死信队列中消息过期后,转发到此队列,真实存储死信队列需要绑定死信交换机和路由
     */
    @Bean
    public Queue realDeadQueue() {
        return new Queue(REAL_DEAD_QUEUE, true, false, false);
    }

    /**
     * 绑定真实存储死信的队列与死信交换机
     */
    @Bean
    public Binding realBindDead() {
        return BindingBuilder.bind(realDeadQueue()).to(deadExchange()).with(ROUTING_KEY).noargs();
            /**
     * 普通的队列,但是指定了死信交换机和路由,在这个队列中的消息过期后会由死信交换机分发到真正的死信队列
     */
    @Bean
    public Queue normalQueue() {
        Map<String, Object> args = new HashMap<>();
        //设置超时时间
        args.put("x-message-ttl",QUEUE_EXPIRE);
        //设置死信参数
        //指定死信交换机
        args.put("x-dead-letter-exchange", EXCHANGE);
        //指定死信路由
        args.put("x-dead-letter-routing-key", ROUTING_KEY);
        return new Queue(NORMAL_QUEUE, true, false, false, args);
    }
    }

二、消费者消费,消费失败之后的逻辑

@Component
@Log4j2
@RabbitListener(queues = REAL_DEAD_QUEUE)
public class PayOrderConsumer {
    @Resource
    OrderMapper orderMapper;
    @Resource
    RabbitTemplate rabbitTemplate;
    @RabbitHandler
    public void receiveDeadMsg(String msg, Channel channel, Message message) throws IOException {
        JSONObject msgJson = JSON.parseObject(msg);
        int count = Integer.parseInt(msgJson.getString("count"));
        Order order=null;
        try {
            log.info("接收到消息:{}",msg);
            //业务逻辑
            ....
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), Boolean.FALSE);
        }catch (Exception e){
            if (count>2){
                log.info("重试次数超过三次失败的消息:{}",msg)
                //发生异常三次重试都失败的时候的业务逻辑
                ....
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), Boolean.FALSE);
                throw e;
            }else {
            	//消费消息失败的时候的逻辑
                log.error("消息{}即将再次返回队列处理...",msg);
                msgJson.put("count",count+1); //计数器
                rabbitTemplate.convertAndSend(NORMAL_EXCHANGE, NORMAL_ROUTING_KEY, msgJson.toString(), new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        MessageProperties messageProperties = message.getMessageProperties();
                        //设置过期时间TTL
                        messageProperties.setExpiration(String.valueOf(EXPIRE));
                        return message;
                    }
                });
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), Boolean.FALSE);
        }
    }

}

三、发送消息

		JSONObject jsonObject = new JSONObject();
        jsonObject.put("msg",orderNumber);
        jsonObject.put("count",0);
        rabbitTemplate.convertAndSend(PayOrderRabbitConfig.NORMAL_EXCHANGE,PayOrderRabbitConfig.NORMAL_ROUTING_KEY,jsonObject);
        log.info("生成订单{}成功",orderNumber);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值