protobuf 3遇到 kryo 的 Map 字段序列化问题

背景

有A ,B,C,D 四个服务 序列化关系如下,其中C服务是一个rpc服务,供很多的服务调用。
在这里插入图片描述

由于我是B服务和C服务的维护者,此时A服务和D服务的通信经由我,由于pb字段协议变更。我这个桥梁不得不做变动。

报错

于是这次增加了一个map字段,意味着你们有变动,放到map,我直接透传就好了。想法很丰满,现实很骨干。

Caused by: com.esotericsoftware.kryo.KryoException: Error during Java serialization.
        at com.esotericsoftware.kryo.serializers.JavaSerializer.write(JavaSerializer.java:33)
        at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:599)
        at de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer.write(UnmodifiableCollectionsSerializer.java:81)
        at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:599)
        at com.esotericsoftware.kryo.serializers.MapSerializer.write(MapSerializer.java:95)
        at com.esotericsoftware.kryo.serializers.MapSerializer.write(MapSerializer.java:21)
        at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:599)
        at org.apache.dubbo.rpc.protocol.dubbo.DubboCodec.encodeRequestData(DubboCodec.java:188)
        at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encodeRequest(ExchangeCodec.java:238)
        at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:69)
        at org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:38)
        at org.apache.dubbo.remoting.transport.netty4.NettyCodecAdapter$InternalEncoder.encode(NettyCodecAdapter.java:70)
        at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:107)
        ... 23 more
Caused by: java.io.NotSerializableException: com.google.protobuf.MapField$MutatabilityAwareMap
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
        at com.esotericsoftware.kryo.serializers.JavaSerializer.write(JavaSerializer.java:30)
        ... 36 more

        at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
        at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
        at org.apache.dubbo.rpc.protocol.dubbo.FutureAdapter.get(FutureAdapter.java:84)
        at sun.reflect.GeneratedMethodAccessor118.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:294)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:248)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:235)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:398)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:205)
        at org.jboss.resteasy.plugins.server.netty.RequestDispatcher.service(RequestDispatcher.java:83)
        at org.jboss.resteasy.plugins.server.netty.RequestHandler.channelRead0(RequestHandler.java:53)
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
        at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:39)
        at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:364)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:418)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:454)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: io.netty.handler.codec.EncoderException: com.esotericsoftware.kryo.KryoException: Error during Java serialization.
io.netty.handler.codec.EncoderException: com.esotericsoftware.kryo.KryoException: Error during Java serialization.
        at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:125)
        at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:749)
        at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:741)
        at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:827)
        at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:734)
        at io.netty.handler.timeout.IdleStateHandler.write(IdleStateHandler.java:286)
        at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:749)
        at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:741)
        at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:827)
        at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:734)
        at io.netty.channel.ChannelDuplexHandler.write(ChannelDuplexHandler.java:106)
        at org.apache.dubbo.remoting.transport.netty4.NettyClientHandler.write(NettyClientHandler.java:87)
        at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:749)
        at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:741)
        at io.netty.channel.AbstractChannelHandlerContext.access$1900(AbstractChannelHandlerContext.java:39)
        at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.write(AbstractChannelHandlerContext.java:1100)
        at io.netty.channel.AbstractChannelHandlerContext$WriteAndFlushTask.write(AbstractChannelHandlerContext.java:1147)
        at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.run(AbstractChannelHandlerContext.java:1089)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:418)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:454)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
        at java.lang.Thread.run(Thread.java:748)


在这里插入图片描述
二话不说,一上来因为我在B服务中代码中是直接把map透传的,此时kryo序列化报错,因为这个内部的mapfield不支持序列化。
在这里插入图片描述
在这里插入图片描述

好咯,开始做转化,把pb3的内部的这个不支持序列化的map手动转为hashmap
在这里插入图片描述
重启服务,上面的错误不报了。出现了新的报错。

在这里插入图片描述
之前是写序列化,这次是C服务里面的报错,但是在B服务中报了。
通过源码追踪,看到,报错出现在下面

在这里插入图片描述

错误发生在给D服务序列化的时候报错了。因为我给D的是hashmap而不是原生的pb内部的map,所以无法初始化这个内部类。在这里插入图片描述

解决

方法1、曲线救国方式,可以通过自定义个repeated message,如下

在这里插入图片描述

后来看源码 ,发现pb内部也是使用这种方式,将map转为list去用的。

在这里插入图片描述

还记得这个内部的map,mutatabilityAwareMap吗?之前就是这个报错的。

方法2,改变C 微服务的rpc的序列化方式为pb,那么此时就可以做到真正的透传!
风险:因为还有很多其他服务在用c服务的接口,所以贸然改动,必定血流才成河。所以,暂时放弃了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章