stackoverflow error导致rabbitmq消费端自动断开

现象:自营的码单信息是通过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解析的类存在递归嵌套 解决办法:去除嵌套即可
http://stackoverflow.com/questions/20987556/gson-stackoverflowerror 模拟递归嵌套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 error导致rabbitmq消费端自动断开》     可以看到,消费端在处理时产生了stackoverflow错误,导致mq消费端断开连接。但是从日志中也看不到请求参数,不好模拟。 5,查看uat环境mq,也存在这种现象,将uat环境mq上的消息都通过界面取出来,将每个请求参数进行模拟调用,模拟出了出现问题的情况,断点跟踪得知是查询数据库的时候出现异常,捕获异常后使用公司日志工具打印warn日志是出现json解析问题
《stackoverflow error导致rabbitmq消费端自动断开》  
《stackoverflow error导致rabbitmq消费端自动断开》   content是exception 内容即是:MyBatisSystemException,他的最终基类是Throwable MyBatisSystemException对象的构造函数如下:
《stackoverflow error导致rabbitmq消费端自动断开》 最终会调用到Throwable的构造函数:
《stackoverflow error导致rabbitmq消费端自动断开》   而Throwable里面有private Throwable cause = this;私有与域,这就形成了对象嵌套,json解析的时候就会出现stackoverflow error 进行json解析是出现ERROR,ERROR是应用try catch捕获不到,mq捕获到了次ERROR,并将aborted设置为true,mq消费端断开连接。   总结:通过上面可以看出,当rabbitmq消费端抛出 ERROR或者InterruptedException,同时业务逻辑中没有对其进行捕获处理,会导致消费端断开mq连接,出现消息积压的情况 。

 

点赞