消费者消息确认
RabbitMQ是閱后即焚機制,RabbitMQ確認消息被消費者消費后會立刻刪除。
而RabbitMQ是通過消費者回執來確認消費者是否成功處理消息的:消費者獲取消息后,應該向RabbitMQ發送ACK回執,表明自己已經處理消息。
設想這樣的場景:
-
1)RabbitMQ投遞消息給消費者
-
2)消費者獲取消息后,返回ACK給RabbitMQ
-
3)RabbitMQ刪除消息
-
4)消費者宕機,消息尚未處理
這樣,消息就丟失了。因此消費者返回ACK的時機非常重要。
而SpringAMQP則允許配置三種確認模式:
?manual:手動ack,需要在業務代碼結束后,調用api發送ack。
?auto:自動ack,由spring監測listener代碼是否出現異常,沒有異常則返回ack;拋出異常則返回nack
?none:關閉ack,MQ假定消費者獲取消息后會成功處理,因此消息投遞后立即被刪除
由此可知:
-
none模式下,消息投遞是不可靠的,可能丟失
-
auto模式類似事務機制,出現異常時返回nack,消息回滾到mq;沒有異常,返回ack
-
manual:自己根據業務情況,判斷什么時候該ack
一般,我們都是使用默認的auto即可。
演示none模式
修改consumer服務的application.yml文件,添加下面內容:
spring:rabbitmq:listener:simple:acknowledge-mode: none # 關閉ack修改consumer服務的SpringRabbitListener類中的方法,模擬一個消息處理異常:
@RabbitListener(queues = "simple.queue") public void listenSimpleQueue(String msg) {log.info("消費者接收到simple.queue的消息:【{}】", msg);// 模擬異常System.out.println(1 / 0);log.debug("消息處理完成!"); }測試可以發現,當消息處理拋異常時,消息依然被RabbitMQ刪除了。
演示auto模式
再次把確認機制修改為auto:
spring:rabbitmq:listener:simple:acknowledge-mode: auto # 關閉ack在異常位置打斷點,再次發送消息,程序卡在斷點時,可以發現此時消息狀態為unack(未確定狀態):
拋出異常后,因為Spring會自動返回nack,所以消息恢復至Ready狀態,并且沒有被RabbitMQ刪除:
總結