背景
有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服务的接口,所以贸然改动,必定血流才成河。所以,暂时放弃了。