RabbitMQ高級特性第4篇-延遲隊列

一、前言

本文演示的延遲隊列是基於SpringBoot整合RabbitMQ來實現的,關於SpringBoot整合RabbitMQ可參考該鏈接:https://blog.csdn.net/pkxwyf/article/details/105158608

二、延遲隊列概述和原理

2.1、什麼是延遲隊列

所謂延遲隊列,即消息進入隊列後不會立即被消費,只有到達指定時間後,纔會被消費。

2.1、延遲隊列應用場景

  • 用戶下單後,30分鐘未支付,取消訂單恢復庫存。

2.3、延遲隊列實現原理

很可惜的是在RabbitMQ中並未提供延遲隊列功能,但是可以使用:TTL+死信隊列 組合實現延遲隊列的效果

三、延遲隊列代碼演示

3.1、消息生產方代碼實現

1、編寫配置類:定義交換機和隊列信息


@Configuration
public class RabbitMQConfig {
    // 普通交換機名稱
    public static final String EXCHANGE_NAME = "order_topic_exchange";
    // 普通隊列名稱
    public static final String QUEUE_NAME = "order_queue";

    // 死信交換機名稱
    public static final String DEAD_EXCHANGE_NAME = "dead_order_topic_exchange";
    // 死信隊列名稱
    public static final String DEAD_QUEUE_NAME = "dead_order_queue";

    // 1. 定義普通交換機
    @Bean("orderExchange")
    public Exchange createExchange(){
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
    }

    // 2. 定義普通隊列
    @Bean("orderQueue")
    public Queue createQueue(){
        // 創建map集合:封裝隊列參數
        Map<String,Object> map = new HashMap<>();
        // 設置死信交換機名稱
        map.put("x-dead-letter-exchange", DEAD_EXCHANGE_NAME);
        // 設置發送給死信交換機的routingKey
        map.put("x-dead-letter-routing-key", "dead.order.news");
        // 設置隊列過期時間:單位毫秒
        map.put("x-message-ttl", 10000);
        return QueueBuilder.durable(QUEUE_NAME).withArguments(map).build();
    }

    // 3. 定義死信交換機
    @Bean("deadOrderExchange")
    public Exchange createDeadExchange(){
        return ExchangeBuilder.topicExchange(DEAD_EXCHANGE_NAME).durable(true).build();
    }

    // 4. 定義死信隊列
    @Bean("deadOrderQueue")
    public Queue createDeadQueue(){
        // 創建map集合:封裝隊列參數
        return QueueBuilder.durable(DEAD_QUEUE_NAME).build();
    }

    // 5. 隊列與交換機綁定關係
    @Bean
    public Binding bindExchangeAndQueue(@Qualifier("orderQueue") Queue queue,
                                        @Qualifier("orderExchange") Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("order.#").noargs();
    }

    // 6. 死信隊列與死信交換機綁定關係
    @Bean
    public Binding bindDeadExchangeAndQueue(@Qualifier("deadOrderQueue") Queue queue,
                                        @Qualifier("deadOrderExchange") Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("dead.order.#").noargs();
    }

}

2、編寫測試類:發送消息到MQ中

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestDelayQueue {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 測試延遲隊列
     */
    @Test
    public void testSendStr() throws Exception{
        // 發送消息
        // 參數1:交換機名字
        // 參數2:路由鍵
        // 參數3:消息字符串
        rabbitTemplate.convertAndSend(
                "order_topic_exchange",
                "order.news",
                "用戶下單成功,訂單ID:1");
    }
}

3.2、消息消費方代碼實現

@Component
public class RabbitMQConfig {
    /**
     * 監聽mq消息
     */
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = "dead_order_topic_exchange",type = "topic"),
            value = @Queue(value = "dead_order_queue",durable = "true"),
            key = "dead.order.#"
    ))
    public void handlerMessage(Message message, Channel channel)throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            // 1. 轉換消息
            System.out.println(new String(message.getBody()));
            // 2. 業務處理
            System.out.println("執行業務處理...");
            System.out.println("根據訂單id查詢狀態...");
            System.out.println("判斷是否支付成功...");
            System.out.println("取消訂單,回滾庫存...");
            // 3. 手工簽收
            channel.basicAck(deliveryTag,true);
        } catch (Exception e) {
            // 4. 拒絕簽收
            channel.basicNack(deliveryTag,true,false);
        }
    }
}

四、延遲隊列小結

  1. 延遲隊列指消息進入隊列後,可以被延遲一定時間再進行消費。
  2. RabbitMQ沒有提供延遲隊列功能,但可以使用:TTL+DLX實現延遲隊列效果。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章