《RabbitMQ》什麼是死信佇列

Java旅途發表於2020-08-07

一 什麼是死信佇列

當一條訊息在佇列中出現以下三種情況的時候,該訊息就會變成一條死信。

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

當訊息在一個佇列中變成一個死信之後,如果配置了死信佇列,它將被重新publish到死信交換機,死信交換機將死信投遞到一個佇列上,這個佇列就是死信佇列。

二 實現死信佇列

2.1 原理圖

死信交換機.png

2.2 建立消費者

建立一個消費者,繫結消費佇列及死信交換機,交換機預設為direct模型,死信交換機也是,arguments繫結死信交換機和key。(註解支援的具體引數文末會附上)

public class DirectConsumer {
    @RabbitListener(bindings = {
            @QueueBinding(value = @Queue(value = "javatrip",arguments = 
                    {@Argument(name="x-dead-letter-exchange",value = "deadExchange"),
                     @Argument(name="x-dead-letter-routing-key",value = "deadKey")
                    }),
                    exchange = @Exchange(value="javatripDirect"),
                    key = {"info","error","warning"}
            )
    })
public void receive1(String message, @Headers Map<String,Object> headers, Channel channel)throws Exception{
    System.out.println("消費者1"+message);
}

2.3 建立生產者

public void publishMessage(String message){

    rabbitTemplate.setMandatory(true);
    rabbitTemplate.convertAndSend("javatripDirect","info",message);
}

三 造成死信的三種情況

3.1 拒絕訊息,並且禁止重新入隊

  1. 設定yml為手動簽收模式
spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual
  1. 設定拒絕訊息並禁止重新入隊
Long deliverTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
channel.basicNack(deliverTag,false,false);
  1. 繫結死信佇列
@RabbitListener(bindings = {
    @QueueBinding(
        value = @Queue(value = "javatripDead"),
        exchange = @Exchange(value = "deadExchange"),
        key = "deadKey"
    )
})
public void receive2(String message){
    System.out.println("我是一條死信:"+message);
}

3.2 訊息TTL過期

繫結業務佇列的時候,增加訊息的過期時長,當訊息過期後,訊息將被轉發到死信佇列中。

@RabbitListener(bindings = {
            @QueueBinding(value = @Queue(value = "javatrip",arguments =
                    {@Argument(name="x-dead-letter-exchange",value = "deadExchange"),
                     @Argument(name="x-dead-letter-routing-key",value = "deadKey"),
                     @Argument(name = "x-message-ttl",value = "3000")
                    }),
                    exchange = @Exchange(value="javatripDirect"),
                    key = {"info","error","warning"}
            )
    })
public void receive1(String message, @Headers Map<String,Object> headers, Channel channel)throws Exception{
    System.out.println("消費者1"+message);
}

3.3 佇列達到最大長度

設定訊息佇列長度,當佇列中的訊息達到最大長度後,繼續傳送訊息,訊息將被轉發到死信佇列中。

@RabbitListener(bindings = {
            @QueueBinding(value = @Queue(value = "javatrip",arguments =
                    {@Argument(name="x-dead-letter-exchange",value = "deadExchange"),
                     @Argument(name="x-dead-letter-routing-key",value = "deadKey"),
                     @Argument(name = "x-max-length",value = "3")
                    }),
                    exchange = @Exchange(value="javatripDirect"),
                    key = {"info","error","warning"}
            )
    })
public void receive1(String message, @Headers Map<String,Object> headers, Channel channel)throws Exception{
    System.out.println("消費者1"+message);
}

四 Spring Boot整合RabbitMQ用到的幾個註解

  1. @QueueBinding作用就是將佇列和交換機進行繫結,主要有以下三個引數:
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface QueueBinding {

	/**
	 * @return the queue.
	 */
	Queue value();

	/**
	 * @return the exchange.
	 */
	Exchange exchange();

	/**
	 * @return the routing key or pattern for the binding.
	 * Multiple elements will result in multiple bindings.
	 */
	String[] key() default {};
}
  1. @Queue是宣告佇列及佇列的一些屬性,主要引數如下:
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Queue {

	/**
	 * @return the queue name or "" for a generated queue name (default).
	 */
	@AliasFor("name")
	String value() default "";

	/**
	 * @return the queue name or "" for a generated queue name (default).
	 * @since 2.0
	 */
	@AliasFor("value")
	String name() default "";

	/**
	 * 是否持久化
	 */
	String durable() default "";

	/**
	 * 是否獨享、排外的.
	 */
	String exclusive() default "";

	/**
	 * 是否自動刪除;
	 */
	String autoDelete() default "";

	/**
	 * 佇列的其他屬性引數
	 * (1)x-message-ttl:訊息的過期時間,單位:毫秒;
         *(2)x-expires:佇列過期時間,佇列在多長時間未被訪問將被刪除,單位:毫秒;
         *(3)x-max-length:佇列最大長度,超過該最大值,則將從佇列頭部開始刪除訊息;
         *(4)x-max-length-bytes:佇列訊息內容佔用最大空間,受限於記憶體大小,超過該閾值則從佇列頭部開始刪除訊息;
         *(5)x-overflow:設定佇列溢位行為。這決定了當達到佇列的最大長度時訊息會發生什麼。有效值是drop-head、reject-publish或reject-publish-dlx。仲裁佇列型別僅支援drop-head;
         *(6)x-dead-letter-exchange:死信交換器名稱,過期或被刪除(因佇列長度超長或因空間超出閾值)的訊息可指定傳送到該交換器中;
         *(7)x-dead-letter-routing-key:死信訊息路由鍵,在訊息傳送到死信交換器時會使用該路由鍵,如果不設定,則使用訊息的原來的路由鍵值
         *(8)x-single-active-consumer:表示佇列是否是單一活動消費者,true時,註冊的消費組內只有一個消費者消費訊息,其他被忽略,false時訊息迴圈分發給所有消費者(預設false)
         *(9)x-max-priority:佇列要支援的最大優先順序數;如果未設定,佇列將不支援訊息優先順序;
         *(10)x-queue-mode(Lazy mode):將佇列設定為延遲模式,在磁碟上保留儘可能多的訊息,以減少RAM的使用;如果未設定,佇列將保留記憶體快取以儘可能快地傳遞訊息;
         *(11)x-queue-master-locator:在叢集模式下設定映象佇列的主節點資訊。
	 */
	Argument[] arguments() default {};
}
  1. @Exchange是宣告交換及交換機的一些屬性,
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Exchange {

	String TRUE = "true";

	String FALSE = "false";

	/**
	 * @return the exchange name.
	 */
	@AliasFor("name")
	String value() default "";

	/**
	 * @return the exchange name.
	 * @since 2.0
	 */
	@AliasFor("value")
	String name() default "";

	/**
	 * 交換機型別,預設DIRECT
	 */
	String type() default ExchangeTypes.DIRECT;

	/**
	 * 是否持久化
	 */
	String durable() default TRUE;

	/**
	 * 是否自動刪除
	 */
	String autoDelete() default FALSE;

	/**
	 * @return the arguments to apply when declaring this exchange.
	 * @since 1.6
	 */
	Argument[] arguments() default {};
}

相關文章