blog

dubbo-version-upgrade とバージョンの互換性

背景\n会社では、一律にダブボを2.6.7にアップグレードする必要があります。\nしかし、アップグレードの際、2.8.x call 2.6.7がエラーを報告するという問題が見つかりました:\n 不明な...

Jun 9, 2020 · 5 min. read
シェア

背景

会社は一律にduboを2.6.7にアップグレードする必要があります。

しかし、アップグレードしたところ、2.8.x(下位バージョン)が2.6.7(上位バージョン)を呼び出す際にエラーを報告するという問題が見つかりました:

java.io.IOException: Unknown result flag, expect '0' '1' '2', get 4

ですから、まず2.8.xを2.6.7にアップデートする必要があります。

注:2.8.xはdangdubboxであり、dangdubは実際には2.5.xをベースにしているので、本質的にはまだローバージョンです。実際には低バージョンを先に高バージョンにアップグレードしないと異常です。

原因

2.6.3以降、サービスプロバイダ側のレスポンスデータのエンコーディングが変更されたため、サービスコンシューマサイドがレスポンスデータをデコードする際にフラグフィールドを識別できず、エラーを報告してしまうことがありました:

java.io.IOException: Unknown result flag, expect '0' '1' '2', get 4
 at 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.5.xをベースに開発されているため、0 1 2しかサポートしておらず、エラーとなります。

dubbo

サービスプロバイダー - DubboCodec(2.6.7)

@Override
protected 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 Request
 boolean 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:1
 out.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 ignore
 int iVersion = getIntVersion(version);
 if (iVersion >= 20010 && iVersion <= 20602) { //消費者側でバージョン2の低いものを扱えるように互換性を持たせる.0.10/020010~2.6.2/020602
 return 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 lishen
 if (in instanceof Cleanable) {
 ((Cleanable) in).cleanup();
 }
 }
}

現在の dubbo バージョン

2.5.8 以下 // バージョン名の一貫性

2.0.1は2.5.10 // 2.5.9以降では2.0.1

2.0.2は2.6.7 // 2.6.3以降では、プロトコルの変更によりバージョンの値は2.0.2となります。

2.8.xはダブボックス // 実際は2.5.xもベースにしているので、実質的にはまだ下位バージョンです

2.8.4以下のプロジェクト

2.8.6以下のプロジェクト

解決方法

2.8.xのアイテムはすべて2.6.7にアップデートするだけで、他のすべての2.5.x、2.6.xは互換性があります。

Read next

1.1wワード | 初級中級フロントエンドJavaScript自己診断チェックリスト - 2

はじめに\nジュニアフロントエンド自己診断チェックリスト-1」では、基本的なことを簡単に説明しましたので、見たことのない方は復習してみてください。\n\nこのパートの内容は、主にオブジェクト、大

Jun 9, 2020 · 5 min read