作者:刘军
全新升级的 Triple 协议
在微服务协议选型方面我们看到越来越多的应用从 Dubbo2 TCP 二进制协议迁移到 Dubbo3 Triple 协议 (兼容 gRPC),以充分利用 Triple 的高效、全双工、Streaming 流式通信模型等能力;Triple+HTTP/2 的组合很好的解决了后端服务穿透性等问题,但在阿里及众多社区企业的实践中,我们发现基于 Triple 构建的微服务对于前端设备接入成本仍然比较高,用户需要通过网关协议转换来接入 Triple 后端服务(类似之前 Dubbo2 泛化调用),对于开发测试、运维等成本都非常高。
基于以上背景,我们对 Dubbo3 中的 Triple 协议进行了全面升级:Triple 协议是 Dubbo3 设计的基于 HTTP 的 RPC 通信协议规范,它完全兼容 gRPC 协议,支持 Request-Response、Streaming 流式等通信模型,可同时运行在 HTTP/1 和 HTTP/2 之上。
你可以使用 cURL 等标准 HTTP 工具访问 Triple 协议发布的服务。
curl \ --header "Content-Type: application/json" \ --data '{"sentence": "Hello Dubbo."}' \ https://host:port/org.apache.dubbo.sample.GreetService/sayHello
基于 Triple 协议,你可以轻松地构建 Dubbo 后端微服务体系,由于 Triple 面向 HTTP 协议的易用性设计,前端设备如 Web、Mobile、标准 HTTP 等可以更轻松的接入后端体系,同时,Triple 与 gRPC 协议完全兼容性可实现与 gRPC 体系的互通。
Dubbo 框架提供了 Triple 协议的多种语言实现,它们可以帮助你构建浏览器、gRPC 兼容的 HTTP API 接口:你只需要定义一个标准的 Protocol Buffer 格式的服务并实现业务逻辑,Dubbo 负责帮助生成语言相关的 Server Stub、Client Stub,并将整个调用流程无缝接入如路由、服务发现等 Dubbo 体系。针对某些语言版本,Dubbo 框架还提供了更贴合语言特性的编程模式,即不绑定 IDL 的服务定义与开发模式,比如在 Dubbo Java 中,你可以选择使用 Java Interface 和 Pojo 类定义 Dubbo 服务,并将其发布为基于 Triple 协议通信的微服务。
协议设计目标与适用场景
基于 Triple 协议,你可以实现以下目标:
当 Dubbo 作为 Client 时
Dubbo Client 可以访问 Dubbo 服务端 (Server) 发布的 Triple 协议服务,同时还可以访问标准的 gRPC 服务端。
- 调用标准 gRPC 服务端,发送 Content-type 为标准 gRPC 类型的请求:application/grpc, application/grpc+proto, and application/grpc+json
- 调用 Dubbo 服务端,发送 Content-type 为 Triple 类型的请求:application/json, application/proto, application/triple+wrapper
当 Dubbo 作为 Server 时
Dubbo Server 默认将同时发布对普通 HTTP、gRPC 协议的支持,Triple 协议可以同时工作在 HTTP/1、HTTP/2 之上。因此,Dubbo Server 可以处理 Dubbo 客户端发过来的 Triple 协议请求,可以处理标准的 gRPC 协议请求,还能处理 cURL、浏览器发送过来的 HTTP 请求。以 Content-type 区分就是:
- 处理 gRPC 客户端发送的 Content-type 为标准 gRPC 类型的请求:application/grpc、application/grpc+proto、application/grpc+json
- 处理 Dubbo 客户端发送的 Content-type 为 Triple 类型的请求:application/json、application/proto、application/grpc+wrapper
- 处理 cURL、浏览器等发送的 Content-type 为 Triple 类型的请求:application/json、application/proto、application/grpc+wrapper
示例场景
Triple 协议按照 gRPC Spec 原生全量支持 Content-Type: application/grpc 协议的通信。基于此模式,Triple Client 可以调用任意的 gRPC Server,反之亦然。Triple 协议支持基于 json 这种通用格式,将任意服务暴露到外部,任何支持标准 HTTP 协议的客户端(如 cURL、浏览器、终端)都可以直接发起调用,无需任何协议转换。Triple 支持将 Java 友好的 Hessian、Kryo 等序列化封装在 HTTP 协议之上,从网络层看来就是一个标准的 HTTP 协议报文,天然兼容任何支持 HTTP 协议的 WAF、Gateway 等,可以很好地复用当前网络层的基础设施。
协议规范(Specification)
请在此查看 Triple 协议规范详情 Triple Specification[1]。
与 gRPC 协议的关系详解
上面提到 Triple 完全兼容 gRPC 协议,那既然 gRPC 官方已经提供了多语言的框架实现,为什么 Dubbo 还要通过 Triple 重新实现一遍那?核心目标主要有以下两点:
- 首先,在协议设计上,Dubbo 参考 gRPC 与 gRPC-Web 两个协议设计了自定义的 Triple 协议:Triple 是一个基于 HTTP 传输层协议的 RPC 协议,它完全兼容 gRPC 的同时可运行在 HTTP/1、HTTP/2 之上。
- 其次,Dubbo 框架在每个语言的实现过程中遵循了符合框架自身定位的设计理念,相比于 grpc-java、grpc-go 等框架库,Dubbo 协议实现更简单、更纯粹,尝试在实现上规避 gRPC 官方库中存在的一系列问题。
gRPC 本身作为 RPC 协议规范非常优秀,但原生的 gRPC 库实现在实际使用存在一系列问题,包括实现复杂、绑定 IDL、难以调试等,Dubbo 在协议设计与实现上从实践出发,很好的规避了这些问题:
- 原生的 gRPC 实现受限于 HTTP/2 交互规范,无法为浏览器、HTTP API 提供交互方式,你需要额外的代理组件如 grpc-web、grpc-gateway 等才能实现。在 Dubbo 中,你可以直接用 curl、浏览器访问 Triple 协议服务。
- gRPC 官方库强制绑定 Protocol Buffers,唯一的开发选择就是使用 IDL 定义和管理服务,这对于一些多语言诉求不强的用户是一个非常大的使用负担。Dubbo 则在支持 IDL 的同时,为 Java、Go 等提供了语言特有的服务定义与开发方式。
- 在开发阶段,以 gRPC 协议发布的服务非常难以调试,你只能使用 gRPC 特定的工具来进行,很多工具都比较简陋 & 不成熟。而从 Dubbo3 开始,你可以直接使用 curl | jq 或者 Chrome 开发者工具来调试你的服务,直接传入 JSON 结构体就能调用服务。
- 首先,gRPC 协议库有超过 10 万行代码的规模,但 Dubbo (Go、Java、Rust、Node.js 等) 关于协议实现部分仅有几千行代码,这让代码维护和问题排查变得更简单。
- 谷歌提供的 gRPC 实现库没有使用主流的第三方或语言官方协议库,而是选择自己维护了一套实现,让整个维护与生态扩展变得更加复杂。比如 grpc-go 自己维护了一套 HTTP/2 库而不是使用的 go 官方库。Dubbo 使用了官方库的同时,相比 gRPC 自行维护的 http 协议库维持了同一性能水准。
- gRPC 库仅仅提供了 RPC 协议实现,需要你做很多额外工作为其引入服务治理能力。而 Dubbo 本身是不绑定协议的微服务开发框架,内置 HTTP/2 协议实现可以与 Dubbo 服务治理能力更好的衔接在一起。
实现更简单
Dubbo 框架实现专注在 Triple 协议自身,而对于底层的网络通信、HTTP/2 协议解析等选择依赖那些经过长期检验的网络库。比如 Dubbo Java 基于 Netty 构建,而 Dubbo Go 则是直接使用的 Go 官方 HTTP 库。Dubbo 提供的 Triple 协议实现非常简单,对应 Dubbo 中的 Protocol 组件实现,你可以仅仅花一下午时间就搞清楚 Dubbo 协议的代码实现。
大规模生产环境检验
自 Dubbo3 发布以来,Triple 协议已被广泛应用于阿里巴巴以及众多社区标杆企业,尤其是一些代理、网关互通场景。一方面 Triple 通过大规模生产实践被证实可靠稳定,另一方面 Triple 的简单、易于调试、不绑定 IDL 的设计也是其得到广泛应用的重要因素。
原生多协议支持
当以 Dubbo 框架为服务端对外发布服务时,可以做到在同一端口原生支持 Triple、gRPC 和 HTTP/1 协议,这意味着你可以用多种形式访问 Dubbo 服务端发布的服务,所有请求形式最终都会被转发到相同的业务逻辑实现,这给你提供了更大的灵活性。Dubbo 完全兼容 gRPC 协议及相关特性包括 streaming、trailers、error details 等,你选择直接在 Dubbo 框架中使用 Triple 协议(另外,你也可以选择使用原生的 gRPC 协议),然后你就可以直接使用 Dubbo 客户端、curl、浏览器等访问你发布的服务。在与 gRPC 生态互操作性方面,任何标准的 gRPC 客户端,都可以正常访问 Dubbo 服务;Dubbo 客户端也可以调用任何标准的 gRPC 服务,这里有提供的互操作性示例[2]以下是使用 cURL 客户端访问 Dubbo 服务端 Triple 协议服务的示例:
curl \ --header "Content-Type: application/json" \ --data '{"sentence": "Hello Dubbo."}' \ https://host:port/org.apache.dubbo.sample.GreetService/sayHello
一站式服务治理接入
我们都知道 Dubbo 有丰富的微服务治理能力,比如服务发现、负载均衡、流量管控等,这也是我们使用 Dubbo 框架开发应用的优势所在。要想在 Dubbo 体系下使用 gRPC 协议通信,有两种方式可以实现,一种是直接在 Dubbo 框架中引入 gRPC 官方发布的二进制包,另一种是在 Dubbo 内原生提供 gRPC 协议兼容的源码实现。相比于第一种引入二进制依赖的方式,Dubbo 框架通过内置 Triple 协议实现的方式,原生支持了 gRPC 协议,这种方式的优势在于源码完全由自己掌控,因此协议的实现与 Dubbo 框架结合更为紧密,能够更灵活的接入 Dubbo 的服务治理体系。
多语言实现
基于 Triple 协议设计,我们计划为尽可能多的语言提供轻量的 RPC 协议实现,让 Triple 协议互通可以完整的覆盖多套语言栈,与 gRPC 兼容且具备更好的易用性。同时,Dubbo 会继续在一些被广泛用于微服务开发的语言(如Java、Go等)提供完善的微服务治理能力,让 Dubbo 成为一套可以连接前后端的微服务开发体系。
当前,Dubbo Java 语言已经在 3.3.0-triple-SNAPSHOT 版本完成了以上 Triple 协议升级的初步目标,具体可在 samples/dubbo-samples-triple-unary 示例中体验(可点击阅读原文跳转到示例链接)。Triple 协议同步推进中的多语言实现还包括:Go、Node.js、Rust 等后端实现,Javascript Web 端实现。
Java 语言
在 Dubbo Java 库实现中,除了 IDL 方式外,你可以使用 Java Interface 方式定义服务,这对于众多熟悉 Dubbo 体系的 Java 用户来说,可以大大降低使用 gRPC 协议的成本。
另外,Java 版本的协议实现在性能上与 grpc-java 库基本持平,甚至某些场景下比 grpc-java 性能表现还要出色。而这一切还是建立在 Dubbo 版本协议的实现复杂度远小于 gRPC 版本的情况下,因为 grpc-java 维护了一套定制版本的 HTTP/2 协议实现。
仓库地址:https://github.com/apache/dubbo
Go 语言实现Dubbo Go 推荐 IDL 开发模式,通过 Dubbo 配套的 protoc 插件生成 stub 代码,你只需要提供对应的业务逻辑实现即可,你可以通过 curl、浏览器访问 Dubbo Go 发布的 gRPC 服务。仓库地址:https://github.com/apache/dubbo-go/
Rust
Dubbo Rust 已经完整实现了 gRPC 协议兼容部分,目前正在推进 HTTP/1 等模式下的 unary RPC 调用支持。
仓库地址:https://github.com/apache/dubbo-rust/
Node.js
Node.js 语言已经完整实现了 gRPC 协议兼容部分,目前正在推进 HTTP/1 等模式下的 unary RPC 调用支持。
仓库地址:https://github.com/apache/dubbo-js/
Web
通过 Dubbo 提供的 Javascript 客户端库,让你可以编写运行在浏览器中的前端页面,在浏览器侧直接发起对后端 Dubbo 服务的请求调用。仓库地址:https://github.com/apache/dubbo-js/
总结
欢迎大家持续关注,对这部分建设感兴趣的开发者,请搜索钉钉群号:37290003945 加入 ApacheDubbo 社区交流群持续关注各个项目开发进展,探索构建基于 HTTP 的高效且具备高度易用性的项目。
相关链接:
[1] Triple Specification
https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/triple-spec/
[2] 互操作性示例