RabbitMQ 高階 - 死信佇列

HuDu發表於2021-06-08

概述

DLX,全稱為 Dead-Letter-Exchange,可以稱之為死信交換機,也有人稱之為死信郵箱。當訊息在一個佇列中變成死信(dead message)之後,他能被重新傳送到另一個交換機中,這個交換機就是 DLX,繫結 DLX 的佇列就稱之為死信佇列。訊息變成死信,可能是由以下的原因

訊息被拒絕
訊息過期
佇列達到最大長度

DLX 也是一個正常的交換機,和一般的交換機沒喲區別,他能在任何的佇列上被指定,實際上就是設定某一個佇列的屬性。當這個佇列中存在死信時,RabbitMQ 就會自動將這個訊息重新發布到設定的 DLX 上去,進而被路由到另一個佇列,即死信佇列。
想要使用死信佇列,只需要在定義佇列的時候設定佇列引數 `x-dead-letter-exchange` 指定交換機即可。

頁面中可以看到引數配置

RabbitMQ 高階 - 死信佇列

死信佇列配置

這就是一個普通的 direct 型別的訊息佇列

@Configuration
public class DeadRabbitMqConfiguration {
    @Bean
    public DirectExchange deadDirectExchange() {
        return new DirectExchange("dead_direct_exchange",true,false);
    }

    @Bean
    public Queue directDeadQueue() {
        return new Queue("dead.direct.queue",true);
    }

    @Bean
    public Binding deadBinding() {
        return BindingBuilder.bind(directDeadQueue()).to(deadDirectExchange()).with("dead");
    }

}

過期訊息佇列配置

相比於之前的訊息佇列,區別在於不僅指定過期時間,還指定了死信佇列交換機以及死信佇列名稱。

@Configuration
public class TTLRabbitMqConfiguration {
    @Bean
    public DirectExchange ttlDirectExchange() {
        return new DirectExchange("ttl_direct_order_exchange",true,false);
    }

//    @Bean
//    public Queue directTtlQueue() {
//        // 設定過期時間
//        HashMap<String, Object> args = new HashMap<>();
//        args.put("x-message-ttl",5000); // 這裡一定是一個int型別
//        return new Queue("ttl.direct.queue",true,false,false,args);
//    }

    @Bean
    public Queue directTtlQueue() {
        // 設定過期時間
        HashMap<String, Object> args = new HashMap<>();
        args.put("x-message-ttl",5000); // 這裡一定是一個int型別
        args.put("x-dead-letter-exchange","dead_direct_exchange");
        args.put("x-dead-letter-routing-key","dead"); // 如果是 fanout 模式,是沒有路由 key 的
        return new Queue("ttl2.direct.queue",true,false,false,args);
    }

    @Bean
    public Queue directTtlMessageQueue() {
        return new Queue("ttl.message.direct.queue",true);
    }

    @Bean
    public Binding ttlBinding() {
        return BindingBuilder.bind(directTtlQueue()).to(ttlDirectExchange()).with("ttl2");
    }


    @Bean
    public Binding ttlMessageBinding() {
        return BindingBuilder.bind(directTtlMessageQueue()).to(ttlDirectExchange()).with("ttlMessage");
    }

}

測試

/**
     * 佇列設定過期時間
     * @param userId
     * @param productId
     * @param num
     */
    public void makeOrderTtl2(String userId,String productId,int num) {
        // 1:根據id查詢商品是否充足
        // 2:儲存訂單
        String orderId = UUID.randomUUID().toString();
        System.out.println("訂單生成成功:"+orderId);
        // 3:通過 MQ 來完成訊息的分發
        // 交換機,路由 key/queue 佇列名稱,訊息內容
        String exchangeName = "ttl_direct_order_exchange";
        String routingKey = "ttl2";
        rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId);
    }

@Test
void testOrderTtl2() {
  orderService.makeOrderTtl2("1","1",12);
}

RabbitMQ 高階 - 死信佇列

RabbitMQ 高階 - 死信佇列

可以看到這個佇列多了兩個引數DLXDLK

過期的訊息被投遞到ttl2.direct.queue死信佇列

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章