SpringCloud+SpringBoot b2b2c 微服務商城電商之RabbitMQ Dead-Letter-Queue 詳解(產生、處理了過程及設置)

大型分佈式微服務雲架構及電子商務平臺都離不開RabbitMQ消息中間件,我們的電子商務平臺中,在不同的業務應用場景下就使用消息中間件,今天我對消息中間件的死信隊列做一下總結,希望能夠幫助到更多的朋友,總結如下:

死信隊列介紹

  • 死信隊列:DLX,dead-letter-exchange
  • 利用DLX,當消息在一個隊列中變成死信 (dead message) 之後,它能被重新publish到另一個Exchange,這個Exchange就是DLX

消息變成死信有以下幾種情況

  • 消息被拒絕(basic.reject / basic.nack),並且requeue = false
  • 消息TTL過期
  • 隊列達到最大長度

死信處理過程

  • DLX也是一個正常的Exchange,和一般的Exchange沒有區別,它能在任何的隊列上被指定,實際上就是設置某個隊列的屬性。
  • 當這個隊列中有死信時,RabbitMQ就會自動的將這個消息重新發布到設置的Exchange上去,進而被路由到另一個隊列。
  • 可以監聽這個隊列中的消息做相應的處理。

死信隊列設置

  1. 首先需要設置死信隊列的exchange和queue,然後進行綁定:
Exchange: dlx.exchange
Queue: dlx.queue
RoutingKey: #
#表示只要有消息到達了Exchange,那麼都會路由到這個queue上
  1. 然後需要有一個監聽,去監聽這個隊列進行處理
  2. 然後我們進行正常聲明交換機、隊列、綁定,只不過我們需要在隊列加上一個參數即可:arguments.put(" x-dead-letter-exchange","dlx.exchange");,這樣消息在過期、requeue、 隊列在達到最大長度時,消息就可以直接路由到死信隊列!

死信隊列演示

1. 消息生產者

public class Producer {

    public static void main(String[] args) throws Exception {
        //1 創建ConnectionFactory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.43.157");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        //2 獲取Connection
        Connection connection = connectionFactory.newConnection();
        //3 通過Connection創建一個新的Channel
        Channel channel = connection.createChannel();
        
        String exchange = "test_dlx_exchange";
        String routingKey = "dlx.save";
        
        String msg = "Hello RabbitMQ DLX Message";
        
        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                .deliveryMode(2)
                .contentEncoding("UTF-8")
                .expiration("10000")
                .build();
        //發送消息
        channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes());
    }
}

2. 自定義消費者

public class MyConsumer extends DefaultConsumer {

    public MyConsumer(Channel channel) {
        super(channel);
    }

    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.err.println("-----------consume message----------");
        System.err.println("consumerTag: " + consumerTag);
        System.err.println("envelope: " + envelope);
        System.err.println("properties: " + properties);
        System.err.println("body: " + new String(body));
    }
}

3. 消費端

  • 聲明正常處理消息的交換機、隊列及綁定規則
  • 在正常交換機上指定死信發送的Exchange
  • 聲明死信交換機、隊列及綁定規則
  • 監聽死信隊列,進行後續處理,這裏省略
public class Consumer {

    public static void main(String[] args) throws Exception {
        
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.43.157");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        
        // 聲明一個普通的交換機 和 隊列 以及路由
        String exchangeName = "test_dlx_exchange";
        String routingKey = "dlx.#";
        String queueName = "test_dlx_queue";
        
        channel.exchangeDeclare(exchangeName, "topic", true, false, null);
        //指定死信發送的Exchange
        Map<String, Object> agruments = new HashMap<String, Object>();
        agruments.put("x-dead-letter-exchange", "dlx.exchange");
        //這個agruments屬性,要設置到聲明隊列上
        channel.queueDeclare(queueName, true, false, false, agruments);
        channel.queueBind(queueName, exchangeName, routingKey);
        
        //要進行死信隊列的聲明
        channel.exchangeDeclare("dlx.exchange", "topic", true, false, null);
        channel.queueDeclare("dlx.queue", true, false, false, null);
        channel.queueBind("dlx.queue", "dlx.exchange", "#");
        
        channel.basicConsume(queueName, true, new MyConsumer(channel));
    }
}

運行說明

啓動消費端,此時查看管控臺,新增了兩個Exchange,兩個Queue。在test_dlx_queue上我們設置了DLX,也就代表死信消息會發送到指定的Exchange上,最終其實會路由到dlx.queue上。

此時關閉消費端,然後啓動生產端,查看管控臺隊列的消息情況, test_dlx_queue的值爲1,而 dlx_queue的值爲0。
10s後的隊列結果如圖,由於生產端發送消息時指定了消息的過期時間爲10s,而此時沒有消費端進行消費,消息便被路由到死信隊列中。
 

實際環境我們還需要對死信隊列進行一個監聽和處理,當然具體的處理邏輯和業務相關,這裏只是簡單演示死信隊列是否生效。希望能夠幫助更多的朋友瞭解RabbitMQ死信隊列

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章