dubbo-版本升级和版本兼容
背景
公司需要统一升级dubbo为2.6.7。
但是升级的时候,发现问题:2.8.x调用2.6.7报错。所以需要先更新2.8.x为2.6.7。
原因
从2.6.3开始服务提供者端对响应数据的编码这一块变了,导致服务消费者端在解码响应数据的时候没有办法识别标志字段,然后就报错:
java.io.IOException: Unknown result flag, expect '0' '1' '2', get 4at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.decode(DecodeableRpcResult.java:101)at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.decode(DecodeableRpcResult.java:109)at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCodec.decodeBody(DubboCodec.java:90)at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:119)at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:80)at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCountCodec.decode(DubboCountCodec.java:46)at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.messageReceived(NettyCodecAdapter.java:134)at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:80)at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559)at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261)at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:349)at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:280)at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:200)at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:44)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)
具体原因是,低版本只支持标志0 1 2,如果消费者版本是2.0.10到2.6.2,高版本提供者2.6.3及以上就会兼容处理,即响应数据的标志是0 1 2。但是现在消费者是2.8.x,导致高版本提供者2.6.3及以上不能兼容处理,即响应数据的标志是4,由于2.8.x其实也是基于低版本2.5.x开发的,所以也只支持0 1 2,结果导致报错。
dubbo源码
服务提供端-DubboCodec(2.6.7)
@Overrideprotected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {Result result = (Result) data;// currently, the version value in Response records the version of Requestboolean attach = Version.isSupportResponseAttatchment(version); //校验Throwable th = result.getException();if (th == null) {Object ret = result.getValue();if (ret == null) {out.writeByte(attach ? RESPONSE_NULL_VALUE_WITH_ATTACHMENTS : RESPONSE_NULL_VALUE);} else {out.writeByte(attach ? RESPONSE_VALUE_WITH_ATTACHMENTS : RESPONSE_VALUE); //attach ? 4:1out.writeObject(ret);}} else {out.writeByte(attach ? RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS : RESPONSE_WITH_EXCEPTION);out.writeObject(th);}if (attach) {// returns current version of Response to consumer side.result.getAttachments().put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());out.writeObject(result.getAttachments());}}
public static boolean isSupportResponseAttatchment(String version) {if (version == null || version.length() == 0) {return false;}// for previous dubbo version(2.0.10/020010~2.6.2/020602), this version is the jar's version, so they need to be ignoreint iVersion = getIntVersion(version);if (iVersion >= 20010 && iVersion <= 20602) { //兼容处理消费者端低版本2.0.10/020010~2.6.2/020602return false;}return iVersion >= LOWEST_VERSION_FOR_RESPONSE_ATTATCHMENT;}
服务消费端-DecodeableRpcResult(2.8.6)
public Object decode(Channel channel, InputStream input) throws IOException {ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType).deserialize(channel.getUrl(), input);try {byte flag = in.readByte();switch (flag) {case DubboCodec.RESPONSE_NULL_VALUE:break;case DubboCodec.RESPONSE_VALUE:try {Type[] returnType = RpcUtils.getReturnTypes(invocation);setValue(returnType == null || returnType.length == 0 ? in.readObject() :(returnType.length == 1 ? in.readObject((Class<?>) returnType[0]): in.readObject((Class<?>) returnType[0], returnType[1])));} catch (ClassNotFoundException e) {throw new IOException(StringUtils.toString("Read response data failed.", e));}break;case DubboCodec.RESPONSE_WITH_EXCEPTION:try {Object obj = in.readObject();if (obj instanceof Throwable == false)throw new IOException("Response data error, expect Throwable, but get " + obj);setException((Throwable) obj);} catch (ClassNotFoundException e) {throw new IOException(StringUtils.toString("Read response data failed.", e));}break;default: //不支持4,所以报错了throw new IOException("Unknown result flag, expect '0' '1' '2', get " + flag);}return this;} finally {// modified by lishenif (in instanceof Cleanable) {((Cleanable) in).cleanup();}}}
当前dubbo版本
2.5.8及以下 //版本名字一致
2.0.1是2.5.10 //从2.5.9及以上开始(即2.5.9到2.5.10),版本的值是2.0.1
2.0.2是2.6.7 //从2.6.3及以上开始,由于协议改了,版本的值是2.0.2
2.8.x是当当dubbox //其实也是基于2.5.x,所以本质还是低版本
2.8.4的项目
2.8.6的项目
解决方法
所有2.8.x项目更新为2.6.7即可,其他的2.5.x、2.6.x都是兼容的。
