01 RPC 协议开发微服务
![]()
在我们正常开发微服务的时候,传统 RPC 服务可能在最底层。上层可能是浏览器、移动端、外界的服务器、自己的测试、curl 等等。我们可能会通过 Tomcat 这种外部服务器去组装我们的 RPC 层,也就是 BFF。或者我们没有 BFF,我们的 RPC 就是对外提供服务。但因为浏览器要访问,所以我们需要有一个网关,比如说 APISIX 或者 ShenYu 等 HTTP 网关。
![]()
上图展示的是我们的流程,但是存在一些问题。
如果我们的服务是非常轻的,我们只需要一个转发层,无论是配网关还是起一个 webserver 去转发,怎么做都很麻烦。
此外,RPC 服务大部分都是基于二进制的,而二进制正常在本地是没法测试的。因此我们的公司内都可能就会开发一种后台或者中间的 Proxy 代理让我们去测试。但这个的前提是你至少得把它部署到测试环境,所以还是没法在本地测试。
总体来说,这两个问题会导致易用性比较低,且开发成本相对较高,因为要做一些与业务无关的重复劳动。
02 全新升级的 Triple 协议
![]()
基于上边的两个问题,我们来介绍一下 Triple 协议。
先来说一下上一代协议,它产出的原因是什么。我们应该都知道 Dubbo 原来是 Dubbo 协议,它是基于 tcp 的,它只有一个包。因为它的包的设计,导致了网关无法做一些特殊规则判断、过滤等操作。但也不是绝对的,如果你愿意牺牲性能把包完全解出来,组装回去再透传还是可以做到的,但一般大家都不太能接受。
所以我们就在想能不能把原数据和真正的包分开。现在我们有现成的 HTTP,又有一个业界主流的 gRPC,所以我们的目标就是兼容 gRPC。因为 gRPC目前都是用 IDL,而 IDL 有一个问题,尤其在 Java 侧。因为大家都是写一些接口,定义一些包去实现,这样就会非常麻烦。Go 侧就还好,因为大家已经习惯了这种开发模式。
所以我们开发了 Triple 协议,首先它兼容了 gRPC,所以我们能实现和 gRPC 的完全互通。其次,我们兼容了自己定义接口的方法。虽然会损失一定的性能,但提升了一些易用性。而且 RPC 一般不是业务的瓶颈,大多数瓶颈还是在 DB。
但还有个问题,虽然我们兼容了 gRPC,但 gRPC 是基于 TPC 的,所以如果前端或者其他第三方系统只有 HTTP,它还是接受不了我们的系统。
![]()
基于此,我们想推出一个全新的 Triple 协议。为了解决上述的所有问题,我们参考了gRPC、gRPC Web、通用 HTTP 等多种协议,做到浏览器访问,支持 Streaming,还支持同时运行在 HTTP/1、HTTP/2 协议上。因为目前 HTTP/3 还没有大规模推广,未来也会支持 HTTP/3。
最终的设计实现是完全基于 HTTP 的,且对人类、开发调试友好。我们可以通过简单的浏览器访问或者 curl 访问,尤其是对 unary RPC。此外,我们和 gRPC 是完全互通的,用 HTTP 的业务不用担心兼容性的问题,也不用担心签协议的问题。为了稳定性,我们只会采用业界流行的网络库,比如 Java 的 native、Go 的基础的 net 包。
![]()
虽然 Triple 协议和 gRPC 协议都基于 HTTP,但 gRPC 是基于 HTTP/2 的,而 Triple 是基于 HTTP/1 和 HTTP/2 的。
我们在兼容 gRPC 的同时,我们为了易用性也扩展了一些功能。比如请求里我们支持 Application/Json 的请求格式,支持使用 curl 访问;
此外上一版的协议,为了支持传统定义接口的方式,我们有一个二次序列化的过程。我们想在这里通过一个特殊的 content type 来决定我们的 body 的结构,解决二次序列化的问题。同时这个东西是可以扩展的,理论上 HTTP 的所有功能我们在 Triple 协议上都可以实现,也可以拓展。
![]()
用了 Triple 协议之后,我们的开发流程也发生了改变。如果你不需要进行组装,或者没有外层的代理,可能你的接入流程就是从外部的请求浏览器、对方的服务器、curl、自己测试等直接到了 server。
和其他的 gRPC 的通信也是没有问题的,流程就相当于少了一层。对于大多数用户,如果你不需要这个场景,其实是有很大的好处。
![]()
Triple 协议因为最开始兼容 gRPC,那个时候只基于 HTTP/2,HTTP/2 有 Streaming 的能力,所以它天然支持 Streaming。但这里比较特殊的是,我们新版的协议在 HTTP/1 也支持了 Stream,但因为 HTTP/1 的限制只能支持到 Server Streaming。依赖 HTTP/1 的 Server Push 实现。
![]()
Client Stream 和 Bi Stream 就没什么可说的了。但有一个特别的是,在 Java 侧没有 Bi Stream,从编码上就没有,但从实现上是有的。
03 Triple 协议开发微服务
![]()
目前 Triple 协议比较灵活的支持两种定义方式,分别是 IDL 定义和直接定义。直接定义支持同步、异步、手写。还有比较极端一点的,比如在自己定义接口的时候使用 IDL 生成 protobuf 的类,我们不定义它的 service,只用它的生成的 request 和 response 类也是没问题的,Triple 协议会自动识别接口使用 protobuf 还是不使用 protobuf 进行传输。
![]()
Server 就是把它的务实现一下。上图是一个例子,我就直接拿了 API 的组装方式,真正的业务上可能是注解或者 XML 的方式。
![]()
因为我们支持了 HTTP 这个标准的协议,理论上我们的测试就会变得很简单。
因为我们支持 gRPC,所以我们可以用 gRPC curl 去调用我们的服务。但前提是你得有反射服务,然后手动开启一下,它不是默认开启的。然后它就可以通过反射拿到接口的源数据,通过 Json 转成 protobuf 格式发过去。或者我们直接用 Application/Json 的方式直接调过去。这里有一点比较特别的是在 HTTP/1 下我们也可以用 Sreaming。
另外,因为我们支持 HTTP,理论上所有第三方的 HTTP 客户端都是可以调用的。然后使用 Dubbo 的 Admin 也可以进行测试,前提是你得把它注册上。
![]()
调用端不管是 POJO 还是 IDL,它们都没有本质的区别。
![]()
现在我们有了 Triple 协议,但如果这个协议没有承载方也是行不通的。因此我们还得有一个框架,有一些服务治理才是我们的微服务。所以服务治理也是微服务中不可或缺的一部分。
04 Dubbo 为 Triple 协议带来治理能力
![]()
Triple 的定位只是 Dubbo 里的其中一个协议,当然你也可以为了兼容性,用原来的 Dubbo 协议或者其他的协议。而且我们支持在同一个端口上开启多个协议,可以按需选择。
![]()
同时 Dubbo 为 Triple 提供了多语言的实现。目前会在 Rust、Go、Java、JS、node、Python 这几部分实现官方的实现。这样用户就不用自己根据实验协议的 spec 去实现了。如果你有一些定制需求,比如内部的一些框架,你根据 spec 实现也是可以的。
![]()
Dubbo 和服务框架集成的很好,理论上在开发流程中,尤其是在 Java 侧服务定义、服务治理、服务注册发现等都不用客户来操心,是开箱即用的。
![]()
Dubbo 提供了丰富的生态,第三方的生态包括 Nacos、Zookeeper 等等,我们不用创新,直接引入相应的包即可。
![]()
这是我们使用 Triple 协议服务注册的例子。上面你可以选 Nacos、Zookeeper、K8s,左边是一个 Client 和一个 Server,这么调用。
![]()
我们在 admin 上看一下实现。这里提一句,我们的 admin 也在新版重构,是用 Go 实现的,大家可以期待一下。
![]()
我们经常会遇到灰度发布或者流量染色的需求。我们可以从 admin 上发一个 tag 治理规则下去,然后把一些实例打上 tag,然后这个携带 tag 的流量就从入口就会挨个传递下去,从而实现全链路的流量染色。
作者:陈有为,陌陌研发工程师、Apache Dubbo PMC
点击立即免费试用云产品 开启云上实践之旅!
原文链接
本文为阿里云原创内容,未经允许不得转载。