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服務的接口,所以貿然改動,必定血流才成河。所以,暫時放棄了。

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