RabbitMq基础及死信队列使用

交换机模式

  1. fanout
    fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
  2. direct
    direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。
  3. topic
    前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但是key可以用模糊匹配。

死信队列

当消费者消费消息的时候,程序服务报错。有如下解决方式:

  1. 重试机制
    在yml中配置重试次数,如果达到次数上限mq会删除该消息
  rabbitmq:
    host: 121.36.44.93
    port: 5672
    username: admin
    password: admin
    listener:
      type: simple
      simple:
        retry:
          max-attempts: 5
          enabled: true
  1. 手动捕获异常,自动ack
  2. 手动捕获异常,手动ack,消息投递到死信队列

普通业务队列,绑定死信交换机

	@Bean
    public Queue systemQueue() {
    
    
        Map<String, Object> args = new HashMap<>(2);
//       x-dead-letter-exchange    这里声明当前队列绑定的死信交换机
        args.put("x-dead-letter-exchange", BizEnum.Message.DLX_EXCHANGE.getType());
//       x-dead-letter-routing-key  这里声明当前队列的死信路由key
        args.put("x-dead-letter-routing-key", "deadLetter.system");
        return QueueBuilder.durable(BizEnum.Message.SYSTEM_QUEUE.getType()).withArguments(args).build();
    }

死信队列

	@Bean
    public Queue deadLetterQueue() {
    
    
        return new Queue(BizEnum.Message.DLX_QUEUE.getType(), true, false, false, null);
    }

死信交换机

	@Bean
    TopicExchange deadLetterExchange() {
    
    
        return new TopicExchange(BizEnum.Message.DLX_EXCHANGE.getType(), true, false, null);
    }

yml配置手动ack

spring:
  rabbitmq:
    host: 121.36.44.93
    port: 5672
    username: admin
    password: admin
    listener:
      type: simple
      simple:
        default-requeue-rejected: false
        acknowledge-mode: manual

业务队列监听

	@RabbitListener(queues = {
    
    "system-queue-ystc2"})
    public void ystc(Message message, com.rabbitmq.client.Channel channel) throws IOException {
    
    
        String msg = new String(message.getBody());
        log.info("收到业务消息A:{}", msg);
        boolean ack = false;
        if (!ack) {
    
    
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        } else {
    
    
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

死信队列监听,可以将错误数据入库,或者不ack,后期再消费该队列数据

	@RabbitListener(queues = {
    
    "dlx-queue-ystc"})
    @Transactional(rollbackFor = Exception.class)
    public void dlMessage(Message message, Channel channel) throws IOException {
    
    
        String msg = new String(message.getBody());
        // 入库或者直接不ack
//        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

猜你喜欢

转载自blog.csdn.net/qq_36382225/article/details/114281245