三、 迁移到 HTTP/2 协议
1. 迁移方案与步骤
1) Triple 介绍
Triple 协议的格式和原理请参阅 RPC 通信协议。
根据 Triple 设计的目标,Triple 协议有以下优势:
• 具备跨语言交互的能力,传统的多语言多 SDK 模式和 Mesh 化跨语言模式都
需要一种更通用易扩展的数据传输协议。
• 提供更完善的请求模型,除了支持传统的 Request/Response 模型(Unary 单向通信),还支持 Stream(流式通信)和 Bidirectional(双向通信)。
• 易扩展、穿透性高,包括但不限于 Tracing/Monitoring 等支持,也应该能被各层设备识别,网关设施等可以识别数据报文,对 Service Mesh 部署友好,降低用户理解难度。
• 完全兼容 grpc,客户端/服务端可以与原生 grpc 客户端打通。
• 可以复用现有 grpc 生态下的组件, 满足云原生场景下的跨语言、跨环境、跨平台的互通需求。
当前使用其他协议的 Dubbo 用户,框架提供了兼容现有序列化方式的迁移能力,在不影响线上已有业务的前提下,迁移协议的成本几乎为零。
需要新增对接 Grpc 服务的 Dubbo 用户,可以直接使用 Triple 协议来实现打通,不需要单独引入 grpc client 来完成,不仅能保留已有的 Dubbo 易用性,也能降低程序的复杂度和开发运维成本,不需要额外进行适配和开发即可接入现有生态。
对于需要网关接入的 Dubbo 用户,Triple 协议提供了更加原生的方式,让网关开发或者使用开源的 grpc 网关组件更加简单。网关可以选择不解析payload,在性能上也有很大提高。在使用 Dubbo 协议时,语言相关的序列化方式是网关的一个很大痛点,而传统的 HTTP 转 Dubbo 的方式对于跨语言序列化几乎是无能为力的。同时,由于 Triple 的协议元数据都存储在请求头中,网关可以轻松的实现定制需求,如路由和限流等功能。
2) Dubbo2 协议迁移流程
Dubbo2 的用户使用 dubbo 协议+自定义序列化,如 hessian2 完成远程调用。
而 Grpc 的默认仅支持 Protobuf 序列化,对于 Java 语言中的多参数以及方法重载也无法支持。
Dubbo3 的之初就有一条目标是完美兼容 Dubbo2,所以为了 Dubbo2 能够平滑升级,Dubbo 框架侧做了很多工作来保证升级的无感,目前默认的序列化和 Dubbo2保持一致为 hessian2。
所以,如果决定要升级到 Dubbo3 的 Triple 协议,只需要修改配置中的协议名称为tri(注意:不是 triple)即可。
接下来我们我们以一个使用 Dubbo2 协议的工程来举例,如何一步一步安全的升级。
• 仅使用 dubbo 协议启动 provider 和 consumer,并完成调用。
• 使用 dubbo 和 tri 协议启动 provider,以 dubbo 协议启动 consumer,并完成调用。
• 仅使用 tri 协议启动 provider 和 consumer,并完成调用。
a) 定义服务
• 定义接口
• 实现类如下
b) 仅使用 dubbo 协议
为保证兼容性,我们先将部分 provider 升级到 dubbo3 版本并使用 dubbo 协议。
使用 dubbo 协议启动一个 Provider 和 Consumer,完成调用,输出如下:
c) 同时使用 dubbo 和 triple 协议
对于线上服务的升级,不可能一蹴而就同时完成 provider 和 consumer 升级,需要按步操作,保证业务稳定。
第二步,provider 提供双协议的方式同时支持 dubbo+tri 两种协议的客户端。
结构如图所示:
注:
按照推荐升级步骤,provider 已经支持了 tri 协议,所以 dubbo3 的 consumer 可以直接使用 tri 协议。
使用 dubbo 协议和 triple 协议启动 Provider 和 Consumer,完成调用,输出如下
d) 仅使用 triple 协议
当所有的 consuemr 都升级至支持 Triple 协议的版本后,provider 可切换至仅使用Triple 协议启动。
结构如图所示:
Provider 和 Consumer 完成调用,输出如下:
e) 实现原理
通过上面介绍的升级过程,我们可以很简单的通过修改协议类型来完成升级。框架是怎么帮我们做到这些的呢?
通过对 Triple 协议的介绍,我们知道 Dubbo3 的 Triple 的数据类型是 protobuf 对象,那为什么非 protobuf 的 java 对象也可以被正常传输呢。
这里 Dubbo3 使用了一个巧妙的设计,首先判断参数类型是否为 protobuf 对象,如果不是。用一个 protobuf 对象将 request 和 response 进行 wrapper,这样就屏蔽了其他各种序列化带来的复杂度。在 wrapper 对象内部声明序列化类型,来支持序列化的扩展。
wrapper 的 protobuf 的 IDL 如下:
对 于 请 求,使用 TripleRequestWrapper 进 行 包 装 , 对 于 响 应使用
TripleResponseWrapper 进行包装。
注:
对于请求参数,可以看到 args 被 repeated 修饰,这是因为需要支持 java 方法的多个参数。当然,序列化只能是一种。序列化的实现沿用 Dubbo2 实现的 spi。
《Apache Dubbo微服务开发从入门到精通》——迁移到 Dubbo3——三、 迁移到 HTTP/2 协议(2) https://developer.aliyun.com/article/1223559