一.TTL (消息的過期時間)
1.兩種設置方式:
(1)通過隊列屬性設置消息過期時間
所有隊列中的消息超過時間未被消費時,都會過期。
@Bean("ttlQueue")
public Queue queue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-message-ttl", 11000); // 隊列中的消息未被消費 11 秒後過期
return new Queue("GP_TTL_QUEUE", true, false, false, map);
}
(2)設置單條消息的過期時間
@Bean("ttlQueue")
public Queue queue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-message-ttl", 11000); // 隊列中的消息未被消費 11 秒後過期
return new Queue("GP_TTL_QUEUE", true, false, false, map);
}
如果同時指定了 Message TTL 和 Queue TTL,則小的那個時間生效。
二.死信隊列
1.什麼情況下消息會變成死信?
1)消息被消費者拒絕並且未設置重回隊列:(NACK || Reject ) && requeue== false
2)消息過期
3)隊列達到最大長度,超過了最大消息數或字節數,最先入隊的消息會被髮送到死信交換機。
2.死信隊列如何使用?
1)聲 明 死 信 交 換 機 、死 信 隊 列,相互綁定
//死信交換機
@Bean("deatLetterExchange")
public TopicExchange deadLetterExchange() {
return new TopicExchange("GP_DEAD_LETTER_EXCHANGE", true, false, new HashMap<>());
}
@Bean("deatLetterQueue")
public Queue deadLetterQueue() {
return new Queue("GP_DEAD_LETTER_QUEUE", true, false, false, new HashMap<>());
}
@Bean
public Binding bindingDead(@Qualifier("deatLetterQueue") Queue queue,@Qualifier("deatLetterExchange")
TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("#"); // 無條件路由
}
2)聲明原交換機、原隊列,相互綁定。隊列中的過期消息,因爲沒有消費者,會變成死信。指定原隊列的死信交換機
//原交換機
@Bean("oriUseExchange")
public DirectExchange exchange() {
return new DirectExchange("GP_ORI_USE_EXCHANGE", true, false, new HashMap<>());
}
@Bean("oriUseQueue")
public Queue queue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-message-ttl", 10000); // 10 秒鐘後成爲死信
map.put("x-dead-letter-exchange", "GP_DEAD_LETTER_EXCHANGE"); // 隊列中的消息變成死信後,進入死信
return new Queue("GP_ORI_USE_QUEUE", true, false, false, map);
}
//綁定
@Bean
public Binding binding(@Qualifier("oriUseQueue") Queue queue,@Qualifier("oriUseExchange") DirectExchange
exchange) {
return BindingBuilder.bind(queue).to(exchange).with("test.ori.use");
}
3)最終消費者監聽死信隊列。
4)生產者發送消息。
三.服務端流控
隊列有兩個控制長度的屬性:x-max-length:隊列中最大存儲最大消息數,超過這個數量,隊頭的消息會被丟棄。x-max-length-bytes:隊列中存儲的最大消息容量,超過這個容量,隊頭的消息會被丟棄。通過設置隊列長度在消息堆積的情況下會刪除先入隊的消息。但如何在消息的產生速度遠大於消費速度的情況下實現服務限流呢。
1.內存控制
RabbitMQ 會在啓動時檢測機器的物理內存數值。默認當 MQ 佔用 40% 以上內存時,MQ 會主動拋出一個內存警告並阻塞所有連接。可以通過修改rabbitmq.config 文件來調整內存閾值,默認值是 0.4,如下所示: {vm_memory_high_watermark, 0.4}。如果設置成0,則所有消息都不能發佈。
2.磁盤控制
通過磁盤來控制消息的發佈。當磁盤空間低於指定的值時(默認50MB),觸發流控措施。
disk_free_limit.relative = 3.0
disk_free_limit.absolute = 2GB
四.消費端限流
默認情況下,如果不進行配置,RabbitMQ會盡可能快速地把隊列中的消息發送消費者,在消費者處理消息的能力有限:消費者數量太少,或者單條消息的處理時間過長。我們需要在一定數量的消息消費完之前,不再推送消息過來,就要對消費端進行流量限制措施,設置消費端最大的可緩存消息數目,超過這個數值的消息不被確認,RabbitMQ會停止投遞新的消息給消費者。
第一種:基於channel設置
channel.basicQos(2); // 如果超過 2 條消息沒有發送 ACK,當前消費者不再接受隊列消息 channel.basicConsume(QUEUE_NAME, false, consumer);
第二種:Spring Boot 配置:
spring.rabbitmq.listener.simple.prefetch=2