Dubbo3 是在云原生背景下诞生的,使用 Dubbo 构建的微服务遵循云原生思想,能更好的复用底层云原生基础设施、贴合云原生微服务架构。这体现在:
- 服务支持部署在容器、Kubernetes平台,服务生命周期可实现与平台调度周期对齐;
- 支持经典 Service Mesh 微服务架构,引入了 Proxyless Mesh 架构,进一步简化 Mesh 的落地与迁移成本,提供更灵活的选择;
- 作为桥接层,支持与 SpringCloud、gRPC 等异构微服务体系的互调互通
一站式微服务解决方案
Dubbo 提供了从服务定义、服务发现、服务通信到流量管控等几乎所有的服务治理能力,并且尝试从使用上对用户屏蔽底层细节,以提供更好的易用性。
定义服务在 Dubbo 中非常简单与直观,可以选择使用与某种语言绑定的方式(如 Java 中可直接定义 Interface),也可以使用 Protobuf IDL 语言中立的方式。无论选择哪种方式,站在服务消费方的视角,都可以通过 Dubbo 提供的透明代理直接编码。
点对点的服务通信是 Dubbo 提供的另一项基本能力,Dubbo 以 RPC 的方式将请求数据(Request)发送给后端服务,并接收服务端返回的计算结果(Response)。RPC 通信对用户来说是完全透明的,使用者无需关心请求是如何发出去的、发到了哪里,每次调用只需要拿到正确的调用结果就行。同步的 Request-Response 是默认的通信模型,它最简单但却不能覆盖所有的场景,因此,Dubbo 提供更丰富的通信模型:
- 消费端异步请求(Client Side Asynchronous Request-Response)
- 提供端异步执行(Server Side Asynchronous Request-Response)
- 消费端请求流(Request Streaming)
- 提供端响应流(Response Streaming)
- 双向流式通信(Bidirectional Streaming)
Dubbo 的服务发现机制,让微服务组件之间可以独立演进并任意部署,消费端可以在无需感知对端部署位置与 IP 地址的情况下完成通信。Dubbo 提供的是 Client-Based 的服务发现机制,使用者可以有多种方式启用服务发现:
- 使用独立的注册中心组件,如 Nacos、Zookeeper、Consul、Etcd 等。
- 将服务的组织与注册交给底层容器平台,如 Kubernetes,这被理解是一种更云原生的方式
云原生友好
Dubbo 从设计上是完全遵循云原生微服务开发理念的,这体现在多个方面,首先是对云原生基础设施与部署架构的支持,包括 Kubernetes、Service Mesh 等,另一方面,Dubbo 众多核心组件都已面向云原生升级,包括 Triple 协议、统一路由规则、对多语言支持。值得一提的是,如何使用 Dubbo 支持弹性伸缩的服务如 Serverless 也在未来计划之中,这包括利用 Native Image 提高 Dubbo 的启动速度与资源消耗等。
结合当前版本,本节主要从以下两点展开 Dubbo 的云原生特性
- 容器调度平台(Kubernetes)
- Service Mesh
Kubernetes
Dubbo 微服务要支持 Kubernetes 平台调度,最基础的就是实现 dubbo 服务生命周期与容器生命周期的对齐,这包括 Dubbo 的启动、销毁、服务注册等生命周期事件。相比于以往 Dubbo 自行定义生命周期事件,并要求开发人员在运维实践过程中遵守约定,Kubernetes 底层基础设施定义了严格的组件生命周期事件(probe),转而要求 Dubbo 去按约定适配。
Kubernetes Service 是另一个层面的适配,这体现了服务定义与注册向云原生底层基础设施下沉的趋势。在这种模式下,用户不再需要搭建额外的注册中心组件,Dubbo 消费端节点能自动对接到 Kubernetes(API-Server 或 DNS),根据服务名(Kubernetes Service Name) 查询到实例列表(Kubernetes endpoints)。 此时服务是通过标准的 Kubernetes Service API 定义,并被调度到各个节点。
Service Mesh
Service Mesh 在业界得到了广泛的传播与认可,并被认为是下一代的微服务架构,这主要是因为它解决了很多棘手的问题,包括透明升级、多语言、依赖冲突、流量治理等。Service Mesh 的典型架构是通过部署独立的 Sidecar 组件来拦截所有的出口与入口流量,并在 Sidecar 中集成丰富的流量治理策略如负载均衡、路由等,除此之外,Service Mesh 还需要一个控制面(Control Panel)来实现对 Sidecar 流量的管控,即各种策略下发。我们在这里称这种架构为经典 Mesh。
然而任何技术架构都不是完美的,经典 Mesh 在实施层面也面临成本过高的问题
- 需要运维控制面(Control Panel)
- 需要运维 Sidecar
- 需要考虑如何从原有 SDK 迁移到 Sidecar
- 需要考虑引入 Sidecar 后整个链路的性能损耗
为了解决 Sidecar 引入的相关成本问题,Dubbo 引入了另一种变相的 Mesh 架构 - Proxyless Mesh,顾名思义,Proxyless Mesh 就是指没有 Sidecar 的部署,转而由 Dubbo SDK 直接与控制面交互,其架构图如下
可以设想,在不同的组织、不同的发展阶段,未来以 Dubbo 构建的微服务将会允许有三种部署架构:传统 SDK、基于 Sidecar 的 Service Mesh、脱离 Sidecar 的 Proxyless Mesh。基于 Sidecar 的 Service Mesh,即经典的 Mesh 架构,独立的 sidecar 运行时接管所有的流量,脱离 Sidecar 的 Proxyless Mesh,富 SDK 直接通过 xDS 与控制面通信。Dubbo 微服务允许部署在物理机、容器、Kubernetes 平台之上,能做到以 Admin 为控制面,以统一的流量治理规则进行治理
What's New in Dubbo3
全新服务发现模型
相比于 2.x 版本中的基于接口
粒度的服务发现机制,3.x 引入了全新的基于应用粒度的服务发现机制, 新模型带来两方面的巨大优势:
- 进一步提升了 Dubbo3 在大规模集群实践中的性能与稳定性。新模型可大幅提高系统资源利用率,降低 Dubbo 地址的单机内存消耗(50%),降低注册中心集群的存储与推送压力(90%), Dubbo 可支持集群规模步入百万实例层次。
- 打通与其他异构微服务体系的地址互发现障碍。新模型使得 Dubbo3 能实现与异构微服务体系如Spring Cloud、Kubernetes Service、gRPC 等,在地址发现层面的互通, 为连通 Dubbo 与其他微服务体系提供可行方案。
在 Dubbo3 前期版本将会同时提供对两套地址发现模型的支持,以最大程度保证业务升级的兼容性
下一代 RPC 通信协议
定义了全新的 RPC 通信协议 – Triple,一句话概括 Triple:它是基于 HTTP/2 上构建的 RPC 协议,完全兼容 gRPC,并在此基础上扩展出了更丰富的语义。 使用 Triple 协议,用户将获得以下能力
- 更容易到适配网关、Mesh架构,Triple 协议让 Dubbo 更方便的与各种网关、Sidecar 组件配合工作。
- 多语言友好,推荐配合 Protobuf 使用 Triple 协议,使用 IDL 定义服务,使用 Protobuf 编码业务数据。
- 流式通信支持。Triple 协议支持 Request Stream、Response Stream、Bi-direction Stream
云原生
Dubbo3 构建的业务应用可直接部署在 VM、Container、Kubernetes 等平台,Dubbo3 很好的解决了 Dubbo 服务与调度平台之间的生命周期对齐,Dubbo 服务发现地址 与容器平台绑定的问题。
在服务发现层面,Dubbo3 支持与 Kubernetes Native Service 的融合,目前限于 Headless Service。
Dubbo3 规划了两种形态的 Service Mesh 方案,在不同的业务场景、不同的迁移阶段、不同的基础设施保障情况下,Dubbo 都会有 Mesh 方案可供选择, 而这进一步的都可以通过统一的控制面进行治理。
- 经典的基于 Sidecar 的 Service Mesh
- 无 Sidecar 的 Proxyless Mesh
用户在 Dubbo2 中熟知的路由规则,在 3.x 中将被一套统一的流量治理规则取代,这套统一流量规则将覆盖未来 Dubbo3 的 Service Mesh、SDK 等多种部署形态, 实现对整套微服务体系的治理
扩展点分离
Dubbo3 的 maven 也发生了一些变化,org.apache.dubbo:dubbo:3.0.0
将不再是包含所有资源的 all-in-one 包,一些可选的依赖已经作为独立组件单独发布, 因此如果用户使用了不在 dubbo
核心依赖包中的独立组件,如 registry-etcd、rpc-hessian 等,需要为这些组件在 pom.xml 中单独增加依赖包。
服务柔性
Dubbo3.0 的柔性增强以面向失败设计为理念,提供包括精准容量评估、自适应限流、自适应负载均衡的支持,自底向上的分步构建大规模可靠应用。 从单一服务的视角看,服务是压不垮的,稳定的。从分布式视角看,复杂的拓扑不会带来性能的下降,分布式负载均衡能够以最优的方式动态分配流量,保证异构系统能够根据运行时的准确服务容量合理分配请求,从而达到性能最优。
全面的性能提升
对比 2.x 版本,Dubbo3 版本
- 服务发现资源利用率显著提升。
- 对比接口级服务发现,单机常驻内存下降 50%,地址变更期 GC 消耗下降一个数量级 (百次 -> 十次)
- 对比应用级服务发现,单机常驻内存下降 75%,GC 次数趋零
- Dubbo 协议性能持平,Triple 协议在网关、Stream吞吐量方面更具优势。
- Dubbo协议 (3.0 vs 2.x),3.0 实现较 2.x 总体 qps rt 持平,略有提升
- Triple协议 vs Dubbo协议,直连调用场景 Triple 性能并无优势,其优势在网关、Stream调用场景。
以上是使用 IDL 定义服务的一个简单示例,我们可以把它命名为 DemoService.proto
,proto 文件中定义了 RPC 服务名称 DemoService
与方法签名 SayHello (HelloRequest) returns (HelloReply) {}
,同时还定义了方法的入参结构体、出参结构体 HelloRequest
与 HelloReply
。 IDL 格式的服务依赖 Protobuf 编译器,用来生成可以被用户调用的客户端与服务端编程 API,Dubbo 在原生 Protobuf Compiler 的基础上提供了适配多种语言的特有插件,用于适配 Dubbo 框架特有的 API 与编程模型。
使用 Dubbo3 IDL 定义的服务只允许一个入参与出参,这种形式的服务签名有两个优势,一是对多语言实现更友好,二是可以保证服务的向后兼容性,依赖于 Protobuf 序列化的兼容性,我们可以很容易的调整传输的数据结构如增、删字段等,完全不用担心接口的兼容性。
编译服务
根据当前采用的语言,配置相应的 Protobuf 插件,编译后将生产语言相关的服务定义 stub
配置并加载服务
提供端负责提供具体的 Dubbo 服务实现,也就是遵循 RPC 签名所约束的格式,去实现具体的业务逻辑代码。在实现服务之后,要将服务实现注册为标准的 Dubbo 服务, 之后 Dubbo 框架就能根据接收到的请求转发给服务实现,执行方法,并将结果返回。
消费端的配置会更简单一些,只需要声明 IDL 定义的服务为标准的 Dubbo 服务,框架就可以帮助开发者生成相应的 proxy,开发者将完全面向 proxy 编程, 基本上 Dubbo 所有语言的实现都保证了 proxy 依据 IDL 服务定义暴露标准化的接口。