
> **1.消費者從隊列中獲取到消息后,會直接確認簽收,假設消費者宕機或者程序出現異常,數據沒有正常消費,這種情況就會出現數據丟失**。
> 2. 消費模式有兩種:rabbitmq推給消費者(訂閱)、消費者主動拉取
> 3. 除非對消息可靠性要求比較的場景,用這種模式會影響性能
> 4. 如果超過15分鐘,消費者沒有ack,rabbitmq就會再次發送消息
# 1. ack種類
1.回復成功
`channel.basicAck(tag, false);`
2.拒絕,消息重回隊列
channel.basicNack(tag, false, true);
3.拒絕,刪除消息
`channel.basicNack(tag, false, false);`
# 丟棄消息
如果消費端異常,mq會一直發送消息給消費者,造成無限循環,此時:
1.指定死信隊列
2.直接丟棄消息,如下配置
~~~
listener:
simple:
default-requeue-rejected: true
~~~
# 3. 消費端消息確認
1. `none`無應答,rabbitmq默認consumer正確處理所有請求。
2. `AUTO`:consumer自動應答,處理成功(注意:此處的成功確認是沒有發生異常)發出ack,處理失敗發出nack。rabbitmq發出消息后會等待consumer端應答,只有收到ack確定信息后才會將消息在rabbitmq清除掉。收到nack異常信息的處理方法由setDefaultRequeueReject()方法設置,這種模式下,發送錯誤的消息可以恢復。
3. `MANUAL`:基本等同于AUTO模式,區別是需要人為調用方法確認。
## 3.1 手動ack
1. 配置ack為手動確認
~~~
rabbitmq:
host: 192.168.56.10
port: 5672
username: tuna
password: tuna
virtual-host: vTest
# 發送確認
publisher-confirms: true
# 路由失敗回調
publisher-returns: true
template:
# 必須設置成true 消息路由失敗通知監聽者,false 將消息丟棄
mandatory: true
listener:
simple:
# 每次從RabbitMQ獲取的消息數量
prefetch: 1
default-requeue-rejected: false
# 每個隊列啟動的消費者數量
concurrency: 1
# 每個隊列最大的消費者數量
max-concurrency: 1
# 簽收模式為手動簽收-那么需要在代碼中手動ACK
acknowledge-mode: manual
~~~
現在隊列中有21個消息

如下圖啟動了四個消費者,從quene1取出來四條數據,但是沒有ack,同樣queue2和queue3個啟動了兩個消費者

關閉服務后,因為沒有ack,消息會重新進入隊列,就是說一條消息也沒有消費
2. 給其中一個消費者增加手動確認
~~~
@RabbitListener(queues = "queue1")
public void receive1(Message message, Channel channel) throws IOException {
System.out.println("收到死信消息A:" + new String(message.getBody()));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
~~~
重啟服務后,如下圖,quene1的四個消費者有一個可以手動ack,所以一直成功消費,其他三條占著茅坑不拉屎

## 3.2 自動確認
~~~
acknowledge-mode: auto
~~~
重啟服務,所有積壓的消息都被消費掉了

將其中一個消費者,拋出異常
比如說現在有個場景:用戶下訂單,涉及到2個系統,訂單系統和庫存系統,2個系統通過消息隊列會話。
訂單系統會新增一條訂單記錄,然后通知消息到隊列,庫存系統消費隊列里的消息然后去減庫存操作。
現在我的問題是:如果訂單系統沒有問題,但是庫存系統減庫存的時候沒有成功,這個時候應該怎么辦?****
“如果訂單系統沒有問題,但是庫存系統減庫存的時候沒有成功,這個時候應該怎么辦?”
訂單系統作為MQ的消費方,這個時候如果減庫存失敗,就給MQ返回處理失敗的ACK,不同的MQ處理細節不同,但都大同小異,當你返回處理失敗的ACK時,MQ會投遞到RetryQueue進行重試,當重試次數達到一定限制時,會投遞到DeadLetterQueue等待人工或CronJob進行補償處理。
當然,這里還有潛在的另一個問題,消費重復,比如,你處理成功了,但是由于某些原因比如業務處理超時導致回給MQ了消費失敗的ACK,就會導致消費重復的問題,可以在業務方用冥等方式處理。