現象:自營的碼單信息是通過mq異步從wms拉取,但是碼單隊列經常會出現消息積壓或者消息未確認的情況,rabbitmq頁面顯示無消費端,多次重啟應用消費端才連上mq
分析:
1,一開始以為是應用沒連上,重啟多次后暫時問題解決
2,但是基本隔一段時間就會又出現消費端連不上,懷疑是mq配置問題,檢查配置得知,此隊列是自動確認,改為手動確認,但是消息積壓,消費端斷掉的情況還是會出現
3,懷疑是mq其他的配置問題,因為此隊列是生產者和消費者在同一應用里面,connectionFactory使用的是同一個,將生產者和消費者的connectionFactory區分開來,問題還是未解決。
4,查看線上日志:
2017-03-27 14:45:43.070 [SimpleAsyncTaskExecutor-3] ERROR org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer - Consumer thread error, thread abort. java.lang.StackOverflowError: null at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:400) ~[gson-2.2.4.jar:na] at com.google.gson.stream.JsonWriter.value(JsonWriter.java:417) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:362) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:346) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195) ~[gson-2.2.4.jar:na] at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) ~[gson-2.2.4.jar:na]
看到是gson解析的時候出現堆棧溢出錯誤
現象:Handler processing failed; nested exception is
Java.lang.StackOverflowError
原因:gson解析的類存在遞歸嵌套
解決辦法:去除嵌套即可
模擬遞歸嵌套gson解析堆棧溢出的代碼如下:
public static class A{ int d; String b; A a; public int getD() { return d; } public void setD(int d) { this.d = d; } public String getB() { return b; } public void setB(String b) { this.b = b; } public A getA() { return a; } public void setA(A a) { this.a = a; } public static void main(String[] args) {; Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").enableComplexMapKeySerialization().create(); A a = new A(); a.setA(a); a.setB("b"); System.out.println(gson.toJson(a)); }
根據日志定位到mq源碼SimpleMessageListenerContainer的內部類AsyncMessageProcessingConsumer的run方法:

可以看到,消費端在處理時產生了stackoverflow錯誤,導致mq消費端斷開連接。但是從日志中也看不到請求參數,不好模擬。
5,查看uat環境mq,也存在這種現象,將uat環境mq上的消息都通過界面取出來,將每個請求參數進行模擬調用,模擬出了出現問題的情況,斷點跟蹤得知是查詢數據庫的時候出現異常,捕獲異常后使用公司日志工具打印warn日志是出現json解析問題


content是exception 內容即是:MyBatisSystemException,他的最終基類是Throwable
MyBatisSystemException對象的構造函數如下:

最終會調用到Throwable的構造函數:

而Throwable里面有private Throwable cause = this;私有與域,這就形成了對象嵌套,json解析的時候就會出現stackoverflow error
進行json解析是出現ERROR,ERROR是應用try catch捕獲不到,mq捕獲到了次ERROR,並將aborted設置為true,mq消費端斷開連接。
總結:通過上面可以看出,當rabbitmq消費端拋出 ERROR或者InterruptedException,同時業務邏輯中沒有對其進行捕獲處理,會導致消費端斷開mq連接,出現消息積壓的情況 。