现象:自营的码单信息是通过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连接,出现消息积压的情况 。