生產環境中,RabbitMQ 持續積壓消息不進行ack,發生什么了?


  問題:生產環境 rabbitmq 部分客戶端 channel 持續積壓消息不進行ack。

  0. 服務配置rabbitmq 集群(普通集群模式)消費者 三台 消費線程各消費者 10消費者配置 使用 spring-amqp|auto-ack 模式1. 故障發現

  近日有同學發現一個業務隊列存在上千個 unacked 消息,並且有持續上漲的趨勢。

  2. 故障表現

  隊列下其中兩個客戶端的各一個 channel 分別阻塞幾百條數據,並且在持續累加,重啟應用后隊列 unacked 消息全部進入 ready 狀態等待重消費,但是重啟后客戶端依然有 channel 重新開始堆積並且在趨勢上漲。

  3. 問題排查

  排查思路

  檢查 mq 控制台是否是隊列創建問題消費者阻塞是否有規律可循(未ack數據是否有共同特征、阻塞客戶端配置是否有問題)客戶端代碼是否有問題、應用是否有jvm級別故障4. 問題定位

  經過一番篩查,問題定位到了代碼部分,隊列消費代碼並非剛上線,而是在前一日服務重啟后出現的這個問題,重新 review 代碼后發現消費者有使用 CountDownLatch 等待多線程消費結果,CountDownLatch#countDown的調用沒有放到 finally 中執行,並且提交到線程池的任務也沒有使用 try catch 進行包裹。

  到此懷疑是消費線程阻塞到了 CountDownLatch#await 處,異步任務處理時由於偶現異常代碼並未執行到 CountDownLatch#countDown 處,再者由於異步任務未捕獲異常導致錯誤直接拋到 jvm 日志無法記錄錯誤。

  為了驗證這個問題,我們又dump了阻塞服務的棧信息,發現確實有消費者線程阻塞到 CountDownLatch#await 處,問題定位結束。

  5. 解決方案

  從任務處下手添加 catch 記錄日志,並將 CountDownLatch#await 放到 finally 中執行。重啟應用再次觀察,並未出現 unacked 消息,觀察日志也並未出現新添加的 error 日志。

  6.問題拓展

  同一個 channel 為何會阻塞那么多數據?

  線上生產環境采用推模式,rabbitmq 通過 channel 推送消息到客戶端,客戶端采用 LinkedBlockingQueue 做緩存,一個 channel 對應一個消費者線程,當消費者線程阻塞時 LinkedBlockingQueue 作為中轉一直在預存消息,所以會出現很多 unacked 消息。

  為什么僅有部分一兩個 channel 出現堆積?

  線上添加錯誤日志后實際並未出現錯誤打印,懷疑之前異常可能是由於重啟后第一次請求 rpc 偶現調用失敗,猜測暫無法復現,后續需觀察日志。

  總結謹慎使用線程同步,謹防線程死鎖,務必保證線程不會 hang死。自建線程池做好錯誤兜底,不要將異常拋給jvm。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM