死信和TTL(Time To Live)是RabbitMQ中需要慎用的2個特性,它們可能會對性能產生負面影響。
死信
死信是RabbitMQ中的一種消息機制,在消費消息時,如果隊列里的消息滿足以下任意一種情況,那么該消息將成為“死信”。
- “requeue”被設置為“false”,消費者使用“basic.reject”或“basic.nack”否定應答(NACK)消息。
- 消息在隊列的存活時間超過設置的TTL時間。
- 隊列的消息數量已經超過最大隊列長度。
死信消息會被RabbitMQ進行特殊處理,如果配置了死信隊列信息,該消息將會被存儲到死信隊列中,如果沒有配置,該消息將會被丟棄。
更多關于死信的說明,請參考。
使用隊列參數配置死信交換機和路由
為隊列配置死信交換機,并在申明隊列時指定“x-dead-letter-exchange”和“x-dead-letter-routing-key”參數。隊列根據“x-dead-letter-exchange”將死信消息發送到死信交換機中,并根據“x-dead-letter-routing-key”為死信消息設置死信路由Key。
以下示例演示在Java客戶端配置死信交換機和路由:
channel.exchangeDeclare("some.exchange.name", "direct");
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", "some.exchange.name");
args.put("x-dead-letter-routing-key", "some-routing-key");
channel.queueDeclare("myqueue", false, false, false, args);
TTL
TTL即過期時間。RabbitMQ支持設置消息和隊列的TTL,消息的TTL可以通過以下兩種方法設置:
- 通過隊列屬性設置:隊列中所有消息的具有相同的過期時間。
- 對消息本身單獨設置:每條消息可以設置不同的TTL。
如果兩種方法同時使用,以較小的TTL為準。
消息在隊列中的生存時間超過了TTL后,消息會被丟棄,如果隊列設置了死信交換機,丟棄的消息會被轉發到死信交換機,由死信交換機將其路由到死信隊列。
更多關于TTL的說明,請參考。
設置隊列TTL
通過channel.queueDeclare方法中的“x-expires”參數控制隊列被自動刪除前處于未使用狀態的時間。未使用是指隊列中沒有任何消費者,也沒有被重新聲明,并且在過期時間段內也未調用過Basic.Get命令。“x-expires”參數的值必須為非零整數,單位為毫秒。
以下示例演示在Java客戶端設置隊列TTL。
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-expires", 1800000);
channel.queueDeclare("myqueue", false, false, false, args);
設置消息TTL
通過隊列屬性設置消息TTL:在channel.queueDeclare方法中加入“x-message-ttl”參數,此參數的值必須為非零整數,單位為毫秒。
以下示例演示在Java客戶端通過隊列屬性設置消息TTL。
Map<String,Object> arg = new HashMap<String, Object>();
arg.put("x-message-ttl",6000);
channel.queueDeclare("normalQueue",true,false,false,arg);
對消息本身單獨設置TTL:在channel.basicPublish方法中加入“expiration”參數,此參數的值必須為非零整數,單位為毫秒。
以下示例演示在Java客戶端對消息本身單獨設置TTL。
byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.expiration("60000")
.build();
channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);