GitHub user Bughue edited a discussion: Seata multi-version protocol control 
design and discuss

## 1 背景

- 
问题一:seata的通信协议报文结构在0.7.1版本发生了较重大的变化,但并没有对之前的协议做兼容处理,导致旧版本服务端的用户若想升级时只能同时升级服务端和客户端,也就是要么忍受一段时间的不可通信,要么就停机升级了。
- 问题二:协议扩展性有问题,  扩充字段或类型后跟前面协议不兼容。(扩展方式不统一、适配逻辑就会分散在各层级里面,造成混乱,无法管理)
- 过往讨论:https://github.com/seata/seata/pull/4569/files

## 2 新旧版本协议结构分析
[分布式事务SEATA 新旧通信协议结构分析](https://zhuanlan.zhihu.com/p/634199908)

## 3 改造思路概述
当前的第一个目标,应该是新版本的seata-server可以和旧版本的client通信(如果要做新版本的client能和旧版本的server通信道理也类似),我认为我们需要做的是以下几件事
- 新版本server识别旧版本协议
- 新版本server解析旧版本协议
- 新版本server将对方标记为旧版本应用,绑定到channel
- 新版本server向对方发起旧版本的通信报文

第二个目标,是协议扩展性优化
- 跨版本的适配统一到codec里面进行(codec按版本号分离)
- 服务器按照最新版本的message处理业务逻辑

## 4 协议结构兼容设计
#### 4.1 协议结构兼容设计
- 新版本server识别旧版本协议
  - <img width="1179" alt="image" 
src="https://github.com/seata/seata/assets/3788653/789f6d07-153a-43eb-8abf-1023c9130f04";>
  - 参考上图,以及[分布式事务SEATA 新旧通信协议结构分析](https://zhuanlan.zhihu.com/p/634199908) 
可以看出判断第三个byte是能判断协议版本的,因为0.6.1以下版本的这个byte都和现在的1不一样,实际上到达1024甚至更多都不冲突
- 新版本server解析旧版本协议
  - 识别到是旧版本后,按照旧版本的逻辑解释即可。关键的是缺失的字段要给一个能兼容好老版本的默认值
- 新版本server将对方标记为旧版本应用,绑定到channel
  - 在TM/RM注册到TC的时候,TC会记录channel,在这个时候要进行协议版本的保存,方便向他们发出消息
- 新版本server向对方发起旧版本的通信报文
  - 在判断到对方TM/RM是旧版本client时,用旧协议的方式去encode/decode

#### 4.2 扩展性设计优化
- codec按版本分包,明确的把各版本分开
- 服务端解析message对象时(接收):按最新版本codec接收(decode适配)
- 服务端创建message对象时(发送):发送前按版本选择codec(encode适配)
- 识别版本(从头部解析)

```
        boolean isV0 = false;
        in.markReaderIndex();
        byte b0 = in.readByte();
        byte b1 = in.readByte();
        // v1/v2/v3 : b2 = version
        // v0 : 1st byte in FLAG(2byte:0x10/0x20/0x40/0x80)
        byte b2 = in.readByte();
        if (ProtocolConstants.MAGIC_CODE_BYTES[0] == b0
                && ProtocolConstants.MAGIC_CODE_BYTES[1] == b1
                && 0 == b2) {
            isV0 = true;
        }

 
```


## 5 改造前后流程对比(服务端接收)
 - 流程图
![image](https://github.com/apache/incubator-seata/assets/3788653/60710cef-b93b-457d-8178-18623ea87c90)

 - 说明
   - 在serialize和rpc包里都要按版本号新建目录,里面包含各版本的解析
   - 版本号在流程中必须清晰,我们传递的对象又是rpcMessage,所以是建议在里面加一个字段来中途保存版本号
   - 对于message的serialize:v1和后续的v2、v3等等都会保持一致,只有v0有差异


## 6 改造前后流程对比(服务端发送)
 - 流程图
![image](https://github.com/apache/incubator-seata/assets/3788653/583e575b-14a0-40be-972c-2f5fa88572b9)

- 说明
   -  改造点和接收匹配
   - 对于message的serialize:要在启动的时候把各版本codec加入工厂(这部分流程图未体现),然后在发送之前按版本选择codec

## 7 PR
 - https://github.com/apache/incubator-seata/pull/6226



GitHub link: https://github.com/apache/incubator-seata/discussions/5628

----
This is an automatically sent email for dev@seata.apache.org.
To unsubscribe, please send an email to: dev-unsubscr...@seata.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@seata.apache.org
For additional commands, e-mail: dev-h...@seata.apache.org

Reply via email to