Dubbo 與開源中國共同策劃【Dubbo 雲原生之路】系列文章,和你們一塊兒回顧 Apache Dubbo 產品和社區的發展,並展望將來發展。系列文章主要涵蓋 Dubbo 技術解讀、社區運營、應用案例解析三大部分。本篇爲系列第三篇。html
系列文章:git
Dubbo 雲原生之路github
做者:小馬哥(mercyblitz),Java 勸退師,《Spring Boot 編程思想》做者,Apache Dubbo PMC、Spring Cloud Alibaba 項目架構師。目前主要負責阿里集團中間件開源項目、微服務技術實施、架構衍進、基礎設施構建等。
在 Java 微服務生態中,Spring Cloud 成爲了開發人員的首選技術棧,然而隨着實踐的深刻和運用規模的擴大,你們逐漸意識到 Spring Cloud 的侷限性。算法
在服務治理方面,相較於 Dubbo 而言,Spring Cloud 並不成熟。遺憾的是,Dubbo 每每被部分開發者片面地視做服務治理的 RPC 框架,而非微服務基礎設施。即便是那些有意將 Spring Cloud 遷移至 Dubbo 的小夥伴,當面對其中遷移和改造的成本時,不免望而卻步。spring
慶幸的是,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 技術棧涵蓋的特性衆多,所以本文討論的範圍僅限於服務治理部分。apache
本文做爲 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 的這個先期版本展開講解。bootstrap
不管開發人員是 Dubbo 用戶仍是 Spring Cloud 用戶,都能輕鬆地駕馭 Dubbo Spring Cloud,並以接近「零」成本的代價使應用向上遷移。Dubbo Spring Cloud 致力於簡化 Cloud Native 開發成本,提升研發效能以及提高應用性能等目的。api
版本支持
因爲 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 版本關係映射關係:
Spring Cloud |
Spring Cloud Alibaba |
Spring Boot |
Dubbo Spring Boot |
Finchley |
0.2.2.RELEASE |
2.0.x |
2.7.1 |
Greenwich |
2.2.1.RELEASE |
2.1.x |
2.7.1 |
Edgware |
0.1.2.RELEASE |
1.5.x |
:x: Dubbo Spring Cloud 不支持該版本 |
功能特性
因爲 Dubbo Spring Cloud 構建在原生的 Spring Cloud 之上,其服務治理方面的能力可認爲是 Spring Cloud Plus,不只徹底覆蓋 Spring Cloud 原生特性,並且提供更爲穩定和成熟的實現,特性比對以下表所示:
功能組件 |
Spring Cloud |
Dubbo Spring Cloud |
分佈式配置(Distributed configuration) |
Git、Zookeeper、Consul、JDBC |
Spring Cloud 分佈式配置 + Dubbo 配置中心(Dubbo 2.7 開始支持配置中心,可自定義適配) |
服務註冊與發現(Service registration and discovery) |
Eureka、Zookeeper、Consul |
Spring Cloud 原生註冊中心(Spring Cloud 原生註冊中心,除 Eureka、Zookeeper、Consul 以外,還包括 Spring Cloud Alibaba 中的 Nacos)+ Dubbo 原生註冊中心 |
負載均衡(Load balancing) |
Ribbon(隨機、輪詢等算法) |
Dubbo 內建實現(隨機、輪詢等算法 + 權重等特性) |
服務熔斷(Circuit Breakers) |
Spring Cloud Hystrix |
Spring Cloud Hystrix + Alibaba Sentinel 等(Sentinel 已被 Spring Cloud 項目納爲 Circuit Breaker 的候選實現) |
服務調用(Service-to-service calls) |
Open Feign、RestTemplate |
Spring Cloud 服務調用 + Dubbo @Reference |
鏈路跟蹤(Tracing) |
Zipkin、opentracing 等 |
高亮特性
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 服務接口
Dubbo 服務接口是服務提供方與消費方的遠程通信契約,一般由普通的 Java 接口(interface)來聲明,如 EchoService
接口:
public interface EchoService { String echo(String message); }
爲了確保契約的一致性,推薦的作法是將 Dubbo 服務接口打包在第二方或者第三方的 artifact(jar)中,如以上接口就存放在 artifact spring-cloud-dubbo-sample-api 之中。
對於服務提供方而言,不只經過依賴 artifact 的形式引入 Dubbo 服務接口,並且須要將其實現。對應的服務消費端,一樣地須要依賴該 artifact,並以接口調用的方式執行遠程方法。接下來進一步討論怎樣實現 Dubbo 服務提供方和消費方。
實現 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
以上依賴 artifact 說明以下:
spring-cloud-dubbo-sample-api
: 提供EchoService
接口的 artifactspring-boot-actuator
: Spring Boot Production-Ready artifact,間接引入spring-boot
artifactspring-cloud-starter-dubbo
: Dubbo Spring Cloud Starterartifact
,間接引入dubbo-spring-boot-starter
等 artifactspring-cloud-starter-alibaba-nacos-discovery
: Nacos Spring Cloud 服務註冊與發現artifact
值得注意的是,以上 artifact 未指定版本(version),所以,還需顯示地聲明 <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>
注:以上完整的 Maven 依賴配置,請參考 spring-cloud-dubbo-server-sample
pom.xml
文件
完成以上步驟以後,下一步則是實現 Dubbo 服務。
實現 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 服務提供方
在暴露 Dubbo 服務方面,推薦開發人員外部化配置的方式,即指定 Java 服務實現類的掃描基準包。
注:Dubbo Spring Cloud 繼承了 Dubbo Spring Boot 的外部化配置特性,也能夠經過標註 @DubboComponentScan
來實現基準包掃描
同時,Dubbo 遠程服務須要暴露網絡端口,並設定通信協議,完整的 YAML 配置以下所示:
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
以上 YAML 內容,上半部分爲 Dubbo 的配置:
dubbo.scan.base-packages
: 指定 Dubbo 服務實現類的掃描基準包dubbo.protocol
: Dubbo 服務暴露的協議配置,其中子屬性name
爲協議名稱,port
爲協議端口( -1 表示自增端口,從 20880 開始)dubbo.registry
: Dubbo 服務註冊中心配置,其中子屬性address
的值 "spring-cloud://localhost",說明掛載到 Spring Cloud 註冊中心
下半部分則是 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 服務器主機和端口
以上完整的 YAML 配置文件,請參考 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 服務提供方啓動後,下一步實現一個 Dubbo 服務消費方。
實現 Dubbo 服務消費方
因爲 Java 服務就 EchoService
、服務提供方應用 spring-cloud-dubbo-server-sample
以及 Nacos 服務器均已準備完畢。Dubbo 服務消費方 只需初始化服務消費方 Maven 工程 spring-cloud-dubbo-client-sample
以及消費 Dubbo 服務。
初始化 spring-cloud-dubbo-client-sample
Maven 工程
與服務提供方 Maven 工程類,需添加相關 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 應用。
注:以上完整的 Maven 依賴配置,請參考 spring-cloud-dubbo-client-sample
pom.xml
文件
配置 Dubbo 服務消費方
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
因爲當前應用屬於 Web 應用,它會默認地使用 8080 做爲 Web 服務端口,若是須要自定義,可經過屬性 server.port
調整。
注:以上完整的 YAML 配置文件,請參考 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
HTTP 響應爲:
[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 網關簡易實現示例
問題反饋
若是您在使用 Dubbo Spring Cloud 的過程當中遇到任何問題,請在此反饋內容。
進階閱讀
關於更多的 Dubbo Spring Cloud 特性以及設計細節,請關注