Dubbo 3.0 前瞻之:重塑 Spring Cloud 服务治理
Dubbo 与开源中国共同策划【Dubbo 云原生之路】系列文章,和大家一起回顾 Apache Dubbo 产品和社区的发展,并展望未来发展。系列文章主要涵盖 Dubbo 技术解读、社区运营、应用案例解析三大部分。本篇为系列第三篇。
系列文章:
在 Java 微服务生态中,Spring Cloud 成为了开发人员的首选技术栈,然而随着实践的深入和运用规模的扩大,大家逐渐意识到 Spring Cloud 的局限性。
在服务治理方面,相较于 Dubbo 而言,Spring Cloud 并不成熟。遗憾的是,Dubbo 往往被部分开发者片面地视作服务治理的 RPC 框架,而非微服务基础设施。
即使是那些有意将 Spring Cloud 迁移至 Dubbo 的小伙伴,当面对其中迁移和改造的成本时,难免望而却步。
庆幸的是,Dubbo3 的到来将给这一局面带来重要变革,未来 Dubbo Spring Cloud 将无缝对接 Dubbo3 ,作为 Spring Cloud Alibaba 的最核心组件,完全地拥抱 Spring Cloud 技术栈
不但无缝地整合 Spring Cloud 注册中心,包括 Nacos、Eureka、Zookeeper 以及 Consul,而且完全地兼容 Spring Cloud Open Feign 以及 @LoadBalanced RestTemplate
本文将讨论 Dubbo Spring Cloud 对 Spring Cloud 技术栈所带来的革命性变化由于 Spring Cloud 技术栈涵盖的特性众多,因此本文讨论的范围仅限于服务治理部分。
本文作为 Dubbo3 的前瞻,将着重讲解当前版本的 Dubbo Spring Cloud 实现,Dubbo Spring Cloud 得以实现的一个重要基础即是我们前瞻之一提到的应用级服务发现。
应用级服务发现是 Dubbo3 规划中的重要一环,是 Dubbo 与云原生基础设施打通、实现大规模微服务集群的基石。其实 Dubbo 社区早在 2.7.5 版本开始便探索了应用级服务发现,尝试去优化 Dubbo 的服务发现模型
因此 Dubbo Spring Cloud 是基于 Dubbo Spring Boot 2.7.x(从 2.7.0 开始,Dubbo Spring Boot 与 Dubbo 在版本上保持一致)和 Spring Cloud 2.x 开发,而本文也将基于 2.7.x 的这个先期版本展开讲解。
无论开发人员是 Dubbo 用户还是 Spring Cloud 用户,都能轻松地驾驭 Dubbo Spring Cloud,并以接近“零”成本的代价使应用向上迁移。Dubbo Spring Cloud 致力于简化 Cloud Native 开发成本,提高研发效能以及提升应用性能等目的。
版本支持
由于 Spring 官方宣布 Spring Cloud Edgware(下文简称为 “E” 版) 将在 2019 年 8 月 1 日后停止维护13,因此,目前 Dubbo Spring Cloud 发布版本并未对 “E” 版提供支持,仅为 “F” 版 和 “G” 版开发,同时也建议和鼓励 Spring Cloud 用户更新至 “F” 版 或 “G” 版。
同时,Dubbo Spring Cloud 基于 Apache Dubbo Spring Boot 2.7.x 开发(最低 Java 版本为 1.8),提供完整的 Dubbo 注解驱动、外部化配置以及 Production-Ready 的特性。
以下表格将说明 Dubbo Spring Cloud 版本关系映射关系:
功能特性
由于 Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上,其服务治理方面的能力可认为是 Spring Cloud Plus,不仅完全覆盖 Spring Cloud 原生特性,而且提供更为稳定和成熟的实现,特性比对如下表所示:
高亮特性
Dubbo 使用 Spring Cloud 服务注册与发现
Dubbo Spring Cloud 基于 Spring Cloud Commons 抽象实现 Dubbo 服务注册与发现,应用只需增添外部化配置属性 “dubbo.registry.address = spring-cloud://localhost
”,就能轻松地桥接到所有原生 Spring Cloud 注册中心,包括:- Nacos - Eureka - Zookeeper - Consul
注:Dubbo Spring Cloud 将在下个版本支持 Spring Cloud 注册中心与 Dubbo 注册中心并存,提供双注册机制,实现无缝迁移
Dubbo 作为 Spring Cloud 服务调用
默认情况,Spring Cloud Open Feign 以及 @LoadBalancedRestTemplate
作为 Spring Cloud 的两种服务调用方式。
Dubbo Spring Cloud 为其提供了第三种选择,即 Dubbo 服务将作为 Spring Cloud 服务调用的同等公民出现,应用可通过 Apache Dubbo 注解 @Service
和 @Reference
暴露和引用 Dubbo 服务,实现服务间多种协议的通讯。
同时,也可以利用 Dubbo 泛化接口轻松实现服务网关。
Dubbo 服务自省
Dubbo Spring Cloud 引入了全新的服务治理特性 - 服务自省(Service Introspection),其设计目的在于最大化减轻注册中心负载,去 Dubbo 注册元信息中心化。
假设一个 Spring Cloud 应用引入 Dubbo Spring Boot Starter,并暴露 N 个 Dubbo 服务,以 Dubbo Nacos 注册中心 为例,当前应用将注册 N+1 个 Nacos 应用,除 Spring Cloud 应用本身之前,其余 N 个应用均来自于 Dubbo 服务,当 N 越大时,注册中心负载越重。
因此,Dubbo Spring Cloud 应用对注册中心的负载相当于传统 Dubbo 的 N 分之一,在不增加基础设施投入的前提下,理论上,使其集群规模扩大 N 倍。当然,未来的 Dubbo 也将提供服务自省的能力。
Dubbo 迁移 Spring Cloud 服务调用
尽管 Dubbo Spring Cloud 完全地保留了原生 Spring Cloud 服务调用特性,不过 Dubbo 服务治理的能力是 Spring Cloud Open Feign 所不及的,如高性能、高可用以及负载均衡稳定性等方面。
因此,建议开发人员将 Spring Cloud Open Feign 或者 @LoadBalancedRestTemplate
迁移为 Dubbo 服务。考虑到迁移过程并非一蹴而就,因此,Dubbo Spring Cloud 提供了方案,即 @DubboTransported
注解。
该注解能够帮助服务消费端的 Spring Cloud Open Feign 接口以及 @LoadBalanced
RestTemplate
Bean 底层走 Dubbo 调用(可切换 Dubbo 支持的协议)
而服务提供方则只需在原有 @RestController
类上追加 Dubbo @Servce
注解(需要抽取接口)即可
换言之,在不调整 Feign 接口以及 RestTemplate
URL 的前提下,实现无缝迁移。如果迁移时间充分的话,建议使用 Dubbo 服务重构系统中的原生 Spring Cloud 服务的定义。
简单示例
开发 Dubbo Spring Cloud 应用的方法与传统 Dubbo 或 Spring Cloud 应用类似,按照以下步骤就能完整地实现Dubbo 服务提供方和消费方的应用,完整的示例代码请访问一下相关资源
定义 Dubbo 服务接口
EchoService
接口:
public interface EchoService {
String echo(String message);
}
实现 Dubbo 服务提供方
初始化 spring-cloud-dubbo-server-sample
Maven 工程
artifactId
名为 spring-cloud-dubbo-server-sample
的 Maven 工程,并在其 pom.xml
文件中增添 Dubbo Spring Cloud 必要的依赖:
<dependencies>
<!-- Sample API -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencie
-
spring-cloud-dubbo-sample-api
: 提供EchoService
接口的 artifact -
spring-boot-actuator
: Spring Boot Production-Ready artifact,间接引入spring-boot
artifact -
spring-cloud-starter-dubbo
: Dubbo Spring Cloud Starterartifact
,间接引入dubbo-spring-boot-starter
等 artifact -
spring-cloud-starter-alibaba-nacos-discovery
: Nacos Spring Cloud 服务注册与发现artifact
<dependencyManagement>
:
<dependencyManagement>
<dependencies>
<!-- Spring Cloud Alibaba dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
spring-cloud-dubbo-server-sample
pom.xml
文件
实现 Dubbo 服务
EchoService
作为暴露的 Dubbo 服务接口,服务提供方 spring-cloud-dubbo-server-sample
需要将其实现:
@org.apache.dubbo.config.annotation.Service
class EchoServiceImpl implements EchoService {
@Override
public String echo(String message) {
return "[echo] Hello, " + message;
}
}
@org.apache.dubbo.config.annotation.Service
是 Dubbo 服务注解,仅声明该 Java 服务(本地)实现为 Dubbo 服务。因此,下一步需要将其配置 Dubbo 服务(远程)。
配置 Dubbo 服务提供方
@DubboComponentScan
来实现基准包扫描
dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: org.springframework.cloud.alibaba.dubbo.bootstrap
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
port: -1
spring:
application:
# Dubbo 应用名称
name: spring-cloud-alibaba-dubbo-server
cloud:
nacos:
# Nacos 服务发现与注册配置
discovery:
server-addr: 127.0.0.1:8848
-
dubbo.scan.base-packages
: 指定 Dubbo 服务实现类的扫描基准包 -
dubbo.protocol
: Dubbo 服务暴露的协议配置,其中子属性name
为协议名称,port
为协议端口( -1 表示自增端口,从 20880 开始) -
dubbo.registry
: Dubbo 服务注册中心配置,其中子属性address
的值 "spring-cloud://localhost",说明挂载到 Spring Cloud 注册中心
-
spring.application.name
: Spring 应用名称,用于 Spring Cloud 服务注册和发现。> 该值在 Dubbo Spring Cloud 加持下被视作dubbo.application.name
,因此,无需再显示地配置dubbo.application.name
-
spring.cloud.nacos.discovery
: Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring-cloud-dubbo-server-sample
bootstrap.yaml
文件
引导 Dubbo Spring Cloud 服务提供方应用
Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别,如下所示:
@EnableDiscoveryClient @EnableAutoConfiguration public class DubboSpringCloudServerBootstrap {
public static void main(String[] args) {
SpringApplication.run(DubboSpringCloudServerBootstrap.class);
}
}
DubboSpringCloudServerBootstrap
之前,请提前启动 Nacos 服务器。当 DubboSpringCloudServerBootstrap
启动后,将应用 spring-cloud-dubbo-server-sample
将出现在 Nacos 控制台界面。
实现 Dubbo 服务消费方
由于 Java 服务就
EchoService
、服务提供方应用 spring-cloud-dubbo-server-sample
以及 Nacos 服务器均已准备完毕。Dubbo 服务消费方 只需初始化服务消费方 Maven 工程 spring-cloud-dubbo-client-sample
以及消费 Dubbo 服务。
初始化 spring-cloud-dubbo-client-sample
Maven 工程
<dependencyManagement>
<dependencies>
<!-- Spring Cloud Alibaba dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Sample API -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependenc
spring-cloud-dubbo-server-sample
不同的是,当前应用依赖 spring-boot-starter-web
,表明它属于 Web Servlet 应用。
spring-cloud-dubbo-client-sample
pom.xml
文件
配置 Dubbo 服务消费方
spring-cloud-dubbo-client-sample
属于纯服务消费方,因此,所需的外部化配置更精简:
dubbo:
cloud:
subscribed-services: spring-cloud-alibaba-dubbo-server
spring:
application:
# Dubbo 应用名称
name: spring-cloud-alibaba-dubbo-client
cloud:
nacos:
# Nacos 服务发现与注册配置
discovery:
server-addr: 127.0.0.1:8848
spring-cloud-dubbo-server-sample
,除应用名称 spring.application.name
存在差异外,spring-cloud-dubbo-client-sample
新增了属性 dubbo.cloud.subscribed-services
的设置,并且该值为服务提供方应用 "spring-cloud-dubbo-server-sample"。
dubbo.cloud.subscribed-services
: 用于服务消费方订阅服务提供方的应用名称的列表,若需订阅多应用,使用 "," 分割。不推荐使用默认值为 "*",它将订阅所有应用。
dubbo.cloud.subscribed-services
默认值时,日志中将会输出一行警告:
> > Current application will subscribe all services(size:x) in registry, a lot of memory and CPU cycles may be used, > > thus it's strongly recommend you using the externalized property 'dubbo.cloud.subscribed-services' to specify the services
server.port
调整。
spring-cloud-dubbo-client-sample
bootstrap.yaml
文件
引导 Dubbo Spring Cloud 服务消费方应用
为了减少实现步骤,以下引导类将 Dubbo 服务消费以及引导功能合二为一:
@EnableDiscoveryClient
@EnableAutoConfiguration
@RestController
public class DubboSpringCloudClientBootstrap {
@Reference
private EchoService echoService;
@GetMapping("/echo")
public String echo(String message) {
return echoService.echo(message);
}
public static void main(String[] args) {
SpringApplication.run(DubboSpringCloudClientBootstrap.class);
}
DubboSpringCloudClientBootstrap
也作为 REST Endpoint,通过暴露 /echo
Web 服务,消费 Dubbo EchoService
服务。因此, 可通过 curl
命令执行 HTTP GET 方法:
$ curl http://127.0.0.1:8080/echo?message=%E5%B0%8F%E9%A9%AC%E5%93%A5%EF%BC%88mercyblitz%EF%BC%89
[echo] Hello, 小马哥(mercyblitz)
spring-cloud-dubbo-client-sample
通过消费 Dubbo 服务,返回服务提供方 spring-cloud-dubbo-server-sample
运算后的内容。
高阶示例
如果您需要进一步了解 Dubbo Spring Cloud 使用细节,可参考官方 Samples。
-
spring-cloud-dubbo-sample-api:API 模块,存放 Dubbo 服务接口和模型定义 -
spring-cloud-dubbo-provider-web-sample:Dubbo Spring Cloud 服务提供方示例(Web 应用) -
spring-cloud-dubbo-provider-sample:Dubbo Spring Cloud 服务提供方示例(非 Web 应用) -
spring-cloud-dubbo-consumer-sample:Dubbo Spring Cloud 服务消费方示例 -
spring-cloud-dubbo-servlet-gateway-sample:Dubbo Spring Cloud Servlet 网关简易实现示例
觉得不错,请点个在看呀