MQ消息序列化失败排查

来源:互联网 发布:淘宝上买电视可靠吗 编辑:程序博客网 时间:2024/06/04 19:24

MQ消息序列化失败排查


前几天项目环境跟别人联调消息的过程中 发现没有看到预期的消费消息的日志,因此开始找原因。

1.确认消息生产方是否发了消息,找到消息生产方查看了服务器的日志,发现的确有发消息,根据msgId去消息控制平台查阅消息,显示消息已经被消费了。说明消息消费的配置也是没有问题。

2.去订阅消息的服务器上面查找日志,看是否有异常日志的打印,按照条件搜索,果然找到了一个异常

2017-11-22 19:23:40.241 ERROR c.t.a.m.client.to.AsyncMsgRM.getContent:36 AsyncMsgRM deserialize error!com.caucho.hessian.io.HessianProtocolException: unknown code for readObject at 0x63 (c)  at com.caucho.hessian.io.HessianInput.error(HessianInput.java:1697)  at com.caucho.hessian.io.HessianInput.readObject(HessianInput.java:1177)  at com.xxx.async.message.client.util.HessianUtil.deserialize(HessianUtil.java:33)  at com.xxx.async.message.client.to.AsyncMsgRM.getContent(AsyncMsgRM.java:34)  at com.xxx.notify.callback.AbstractNotifyCallBack.filterMsg(AbstractNotifyCallBack.java:91)  at com.xxx.notify.callback.AbstractNotifyCallBack.process(AbstractNotifyCallBack.java:53)  at com.xxx.async.message.client.consumer.support.MultiConsumerHandle.consume(MultiConsumerHandle.java:60)  at com.xxx.async.message.client.consumer.ConsumerListenerForRm$BaseListenerConcurrently.consumeMessage(ConsumerListenerForRm.java:158)  at com.alibaba.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService$ConsumeRequest.run(ConsumeMessageConcurrentlyService.java:146)  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)  at java.util.concurrent.FutureTask.run(FutureTask.java:266)  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)  at java.lang.Thread.run(Thread.java:748)

根据异常堆栈分析:deserialize error说明反序列化失败
远程通讯反序列化 采用的是hessian

3.第一反应是消息体对象没有实现Serializable接口,但是检查了下发现已经实现接口了。
然后想到是不是两边序列化的hession版本不同,但是确认了下版本号是相同的,陷入困境。

再回顾了下消息体对象,终于发现不对劲的地方了,类实现了Serializable接口,但是没有生成对应的serialVersionUID

serialVersionUID的作用是什么呢?
**Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。
类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值**

4.解决方案:让消息生产方生成了一个明确的serialVersionUID重新打包,服务器重新部署之后,问题解决。

通过这个问题,对于序列化和反序列化加深了理解,serialVersionUID非常重要,另外如果已经定义了一个明确的serialVersionUID,提供给别的应用使用,千万不要去改serialVersionUID了。