RabbitMq報錯reply-code=406 reply-text=PRECONDITION_FAILED解決
一、檢查配置是否正確
今天看生產日志發(fā)現了很多的RabbitMq報錯:reply-code=406, reply-text=PRECONDITION_FAILED - unknown delivery tag 1, class-id=60, method-id=80,全都是異常之后重復消費,重復報錯。
unknown delivery tag 1-參考rabbitMQ的tag機制可知這條消息已經完成了消費;那么出現這個原因是配置不對了。
首先排查SimpleRabbitListenerContainerFactory是否加上手動ack
private SimpleRabbitListenerContainerFactory getSimpleRabbitListenerContainerFactory(ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); //使用jackson進行消息序列與反序列 factory.setMessageConverter(new Jackson2JsonMessageConverter()); factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); // 開啟手動 ack return factory; }
Jackson2JsonMessageConverter是rabbitmq 對java對象json序列化的支持,在發(fā)送消息時,會先將自定義的消息類序列化成json格式,再轉成byte構造 Message,rabbitmq的ack就被設置為自動提交;需要手動開啟ack,沒得問題:factory.setAcknowledgeMode(AcknowledgeMode.MANUAL)。
其次檢查配置文件,配置文件設置為手動ack
spring.rabbitmq.listener.direct.acknowledge-mode=manual
rabbitmq: host: 127.0.0.1 port: 5672 username: guest password: guest ###開啟消息確認機制 confirms virtual-host: / publisher-confirms: true publisher-returns: true #rabbitmq配置加上手動應答 listener: simple: acknowledge-mode: manual
二、rabbitmq消息重回隊列,回到隊尾
當出現異常時,我們需要把這個消息回滾到消息隊列,有兩種方式:
- ack返回false,并重新回到隊列channel.basicNack channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
- 拒絕消息channel.basicReject channel.basicReject(message.getMessageProperties().getDeliveryTag(), true)
但是環(huán)境中的實際情況是,當消息回滾到消息隊列時,這條消息不會回到隊列尾部,而是仍是在隊列頭部,這時消費者會立馬又接收到這條消息進行處理,接著拋出異常,進行回滾,如此反復進行。這種情況會導致消息隊列處理出現阻塞,消息堆積,導致正常消息也無法消費。
對于消息回滾到消息隊列,我們希望方式是出現異常的消息到達消息隊列尾部,這樣既保證消息不會丟失,又保證了正常業(yè)務的進行。
因此我們采取的解決方案是,將消息先進行應答,這時消息隊列會刪除該消息,同時再次發(fā)送該消息到消息隊列,這時就實現了錯誤消息進行消息隊列尾部的方案。
具體方案為:
//手動進行應答 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); //重新發(fā)送消息到隊尾 channel.basicPublish(message.getMessageProperties().getReceivedExchange(), message.getMessageProperties().getReceivedRoutingKey(), MessageProperties.PERSISTENT_TEXT_PLAIN, JSON.toJSONBytes(new Object()));
三、消息體本身有誤
如果一個消息體本身有誤,會導致該消息體,一直無法進行處理,而服務器中刷出大量無用日志
解決這個問題可以采取兩種方案:
1、對于日常細致處理,分清哪些是可以恢復的異常,哪些是不可以恢復的異常。對于可以恢復的異常我們采取第三條中的解決方案,對于不可以處理的異常,我們采用記錄日志,直接丟棄該消息方案。
2、對每條消息進行標記,記錄每條消息的處理次數,當一條消息,多次處理仍不能成功時,處理次數到達我們設置的值時,我們就丟棄該消息,但需要記錄詳細的日志。
消息監(jiān)聽內的異常處理有兩種方式:
1、內部catch后直接處理,然后使用channel對消息進行確認
2、配置RepublishMessageRecoverer將處理異常的消息發(fā)送到指定隊列專門處理或記錄。監(jiān)聽的方法內拋出異常貌似沒有太大用處。因為拋出異常就算是重試也非常有可能會繼續(xù)出現異常,當重試次數完了之后消息就只有重啟應用才能接收到了,很有可能導致消息消費不及時。當然可以配置RepublishMessageRecoverer來解決,但是萬一RepublishMessageRecoverer發(fā)送失敗了呢。那就可能造成消息消費不及時了。所以即使需要將處理出現異常的消息統一放到另外隊列去處理,個人建議兩種方式:
- catch異常后,手動發(fā)送到指定隊列,然后使用channel給rabbitmq確認消息已消費
- 給Queue綁定死信隊列,使用nack(requque為false)確認消息消費失敗
以上就是RabbitMq報錯reply-code=406 reply-text=PRECONDITION_FAILED解決的詳細內容,更多關于RabbitMq reply報錯解決的資料請關注腳本之家其它相關文章!
相關文章
Spring Cloud gateway 網關如何攔截Post請求日志
這篇文章主要介紹了Spring Cloud gateway 網關如何攔截Post請求日志的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07淺析Java如何優(yōu)雅的設計接口狀態(tài)碼和異常
HTTP協議里定義了一系列的狀態(tài)碼用來表明請求的狀態(tài),如常用的200表示請求正常,404表示請求的資源不存在,所以本文就來和大家討論一下如何優(yōu)雅的設計接口狀態(tài)碼和異常,感興趣的可以了解下2024-03-03Hadoop環(huán)境配置之hive環(huán)境配置詳解
這篇文章主要介紹了Hadoop環(huán)境配置之hive環(huán)境配置,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-12-12dubbo?filter中有關bean注入和配置文件讀取方式
這篇文章主要介紹了dubbo?filter中有關bean注入和配置文件讀取方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05解決Mybatis-Plus更新方法不更新NULL字段的問題
這篇文章主要介紹了解決Mybatis-Plus更新方法不更新NULL字段的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12