Dubbo很多人都不陌生,這畢竟是一款從2012年就開始開源的Java RPC框架,中間由於各種各樣的原因停止更新4年半的時間,中間只發過一個小版本修了一個小bug,甚至大家都以為這個項目已經死掉了,竟然又在2017年9月份恢復了更新。
網絡上很多人都拿Dubbo和Spring Cloud做對比,可能在大家的心目中,這兩個框架是可以畫上等號的吧。后來在網絡上有一個非常流行的表格,比較詳細的對比了 Spring Cloud 和 Dubbo,表格如下:
Dubbo | SpringCloud | |
服務注冊中心 | Zookeeper | Spring Cloud Netfix Eureka |
服務調用方式 | RPC | REST API |
服務監控 | Dubbo-monitor | Spring Boot Admin |
熔斷器 | 不完善 | Spring Cloud Netflix Hystrix |
服務網關 | 無 | Spring Cloud Netflix Zuul |
分布式配置 | 無 | Spring Cloud Config |
服務跟蹤 | 無 | Spring Cloud Sleuth |
數據流 | 無 | Spring Cloud Stream |
批量任務 | 無 | Spring Cloud Task |
信息總線 | 無 | Spring Cloud Bus |
以上列舉了一些核心部件,當然這里需要申明一點,Dubbo對於上表中總結為“無”的組件不代表不能實現,而只是Dubbo框架自身不提供,需要另外整合以實現對應的功能,這樣看起來確實Dubbo更像是Spring Cloud的一個子集。
Dubbo在國內擁有着巨大的用戶群,大家希望在使用Dubbo的同時享受Spring Cloud的生態,出現各種各樣的整合方案,但是因為服務中心的不同,各種整合方案並不是那么自然,直到Spring Cloud Alibaba這個項目出現,由官方提供了Nacos服務注冊中心后,才將這個問題完美的解決。並且提供了Dubbo和Spring Cloud整合的方案,命名為:Dubbo Spring Cloud。
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 配置中心 |
服務注冊與發現(Service registration and discovery) | Eureka、Zookeeper、Consul | Spring Cloud 原生注冊中心 + Dubbo 原生注冊中心 |
負載均衡(Load balancing) | Ribbon(隨機、輪詢等算法) | Dubbo 內建實現(隨機、輪詢等算法 + 權重等特性) |
服務熔斷(Circuit Breakers) | Spring Cloud Hystrix | Spring Cloud Hystrix + Alibaba Sentinel 等 |
服務調用(Service-to-service calls) | Open Feign、RestTemplate | Spring Cloud 服務調用 + Dubbo @Reference |
鏈路跟蹤(Tracing) | Spring Cloud Sleuth + Zipkin | Zipkin、opentracing 等 |
以上對比表格摘自Dubbo Spring Cloud官方文檔。
而且Dubbo Spring Cloud基於Dubbo Spring Boot 2.7.1 和 Spring Cloud 2.x開發,無論開發人員是Dubbo用戶還是Spring Cloud用戶, 都能輕松地駕馭,並以接近“零”成本的代價使應用向上遷移。Dubbo Spring Cloud致力於簡化雲原生開發成本,以達成提高研發效能以及提升應用性能等目的。
Dubbo Spring Cloud 主要特性
(1)面向接口代理的高性能RPC調用:提供高性能的基於代理的遠程調用能力,服務以接口為粒度,屏蔽了遠程調用底層細節。
(2)智能負載均衡:內置多種負載均衡策略,智能感知下游節點健康狀況,顯著減少調用延遲,提高系統吞吐量。
(3)服務自動注冊與發現:支持多種注冊中心服務,服務實例上下線實時感知。
(4)高度可擴展能力:遵循微內核+插件的設計原則,所有核心能力如Protocol、Transport、Serialization被設計為擴展點,平等對待內置實現和第三方實現。
(5)運行期流量調度:內置條件、腳本等路由策略,通過配置不同的路由規則,輕松實現灰度發布,同機房優先等功能。
(6)可視化的服務治理與運維:提供豐富服務治理、運維工具:隨時查詢服務元數據、服務健康狀態及調用統計,實時下發路由策略、調整配置參數。
Spring Cloud為什么需要RPC?
在Spring Cloud構建的微服務系統中,大多數的開發者使用都是官方提供的Feign組件來進行內部服務通信,這種聲明式的HTTP客戶端使用起來非常的簡潔、方便、優雅,但是有一點,在使用Feign消費服務的時候,相比較Dubbo這種RPC框架而言,性能堪憂。
雖說在微服務架構中,會將按照業務划分的微服務獨立部署,並且運行在各自的進程中。微服務之間的通信更加傾向於使用HTTP這種簡單的通信機制,大多數情況都會使用REST API。這種通信方式非常的簡潔高效,並且和開發平台、語言無關,但是通常情況下,HTTP並不會開啟KeepAlive功能,即當前連接為短連接,短連接的缺點是每次請求都需要建立TCP連接,這使得其效率變的相當低下。
對外部提供REST API服務是一件非常好的事情,但是如果內部調用也是使用HTTP調用方式,就會顯得顯得性能低下,Spring Cloud默認使用的Feign組件進行內部服務調用就是使用的HTTP協議進行調用。這時,我們如果內部服務使用RPC調用,對外使用REST API,將會是一個非常不錯的選擇。恰巧,Dubbo Spring Cloud給了我們這種選擇的實現方式。
SpringCloud+Nacos+Dubbo整合實戰
下面將會以一個簡單的入門案例,介紹一下在使用Nacos作為服務中心,使用Dubbo來實現服務提供方和服務消費方的案例。
(1)服務端接口契約定義
創建普通Maven項目dubbo-sample-api,定義服務端與消費端的接口契約。該項目僅是用於定義Dubbo服務端與消費端的接口契約。這里創建僅為更好的代碼重用以及接口、模型規格控制管理。然后打包成jar包,安裝到私有倉庫,供客戶端與Dubbo服務端接口實現的項目來依賴使用。
pom.xml不用引用任何包。
定義服務端接口類IHelloService:
package com.zxy.dubbo_sample_api; public interface IHelloService { String sayHello(String name); }
然后執行mvn install,將dubbo-sample-api添加到本地倉庫,供其他項目依賴。
(2)服務端服務實現
創建一個SpringBoot項目dubbo-sample-provider。該項目實現上面定義好的接口,並該項目作為服務注冊到服務注冊中心,這里采用nacos,也可以采用ZooKeeper,而且dubbo還可以支持多注冊中心。
工程依賴pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zxy</groupId> <artifactId>dubbo-sample-provider</artifactId> <version>1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> <relativePath/> </parent> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR10</spring-cloud.version> <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version> </properties> <dependencyManagement> <dependencies> <!-- spring-cloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- spring-cloud-alibaba --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- spring boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 熱部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- Nacos Discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- Dubbo --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> </dependency> <!-- 健康監控,必須包含spring-boot-starter-actuator包,不然啟動會報錯 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- 需要實現的服務接口包 --> <dependency> <groupId>com.zxy</groupId> <artifactId>dubbo-sample-api</artifactId> <version>1.0</version> </dependency> </dependencies> </project>
注意:必須包含spring-boot-starter-actuator包,不然啟動會報錯。pom中引入定義服務契約接口的API模塊的包。
實現Dubbo接口IHelloService,新建HelloServiceImpl類,代碼如下:
package com.zxy.dubbo_sample_provider.service; import com.zxy.dubbo_sample_api.IHelloService; import org.apache.dubbo.config.annotation.DubboService; @DubboService public class HelloServiceImpl implements IHelloService { public String sayHello(String name){ return "Hello World:"+ name; } }
注意:這里的@DubboService注解是Dubbo的org.apache.dubbo.config.annotation.DubboService,千萬不要引用錯誤。@DubboService注解僅聲明該Java服務(本地)實現為Dubbo服務。舊版本的dubbo使用該包下的@Service直接,后來為了防止與spring混淆改為了@DubboService。
配置文件application.properties,將Java服務(本地)配置為Dubbo服務(遠程)如下:
#Spring應用名稱,用於SpringCloud服務注冊和發現。該值在Dubbo Spring Cloud加持下被視作dubbo.application.name,因此,無需再顯示地配置dubbo.application.name。 spring.application.name=dubbo-sample-provider server.port=3001 #Dubbo服務實現類的掃描基准包路徑 dubbo.scan.base-packages=com.zxy.dubbo_sample_provider.service #Dubbo服務暴露的協議配置,其中子屬性name為協議名稱,port為協議端口(-1 表示自增端口,從 20880 開始) #因為項目中存在多個服務提供端比如商品服務、會員服務等,這里為了方便設置為了-1 dubbo.protocol.name=dubbo dubbo.protocol.port=-1 #Dubbo服務注冊中心的配置地址,它的值spring-cloud://localhost表示掛載到Spring Cloud注冊中心,不配置的話會提示沒有配置注冊中心的錯誤。 dubbo.registry.address=spring-cloud://localhost #nacos #spring.cloud.nacos.discovery定義Nacos服務發現與注冊配置,其中子屬性server-addr指定Nacos服務器主機和端口。 spring.cloud.nacos.discovery.server-addr=localhost:8848
注意:在暴露Dubbo服務方面,推薦使用外部化配置的方式,即指定Java服務實現類的掃描基准包。
Dubbo Spring Cloud 繼承了 Dubbo Spring Boot 的外部化配置特性,也可以通過標注@DubboComponentScan來實現基准包掃描。
創建應用主類,即項目入口DubboSampleProviderApplication.java文件。如果使用SpringBoot自動創建項目該文件是自動創建的不用做任何修改。
package com.zxy.dubbo_sample_provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DubboSampleProviderApplication { public static void main(String[] args) { SpringApplication.run(DubboSampleProviderApplication.class, args); } }
運行dubbo-sample-provider項目,將會在Nacos中注冊服務。(注意:在運行項目前,先安裝並啟動Nacos服務端)

(3)消費端(客戶端)實現
創建一個SpringBoot項目dubbo-consumer,實現調用以上的服務。
工程依賴pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zxy</groupId> <artifactId>dubbo-consumer</artifactId> <version>1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> <relativePath/> </parent> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR10</spring-cloud.version> <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version> </properties> <dependencyManagement> <dependencies> <!-- spring-cloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- spring-cloud-alibaba --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- spring boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 熱部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- web項目 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Nacos Discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- Dubbo --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> </dependency> <!-- 健康監控,必須包含spring-boot-starter-actuator包,不然啟動會報錯 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- dubbo服務接口契約包 --> <dependency> <groupId>com.zxy</groupId> <artifactId>dubbo-sample-api</artifactId> <version>1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
注意:pom中一定要引入定義服務契約接口的API模塊的包dubbo-sample-api。
工程配置application.properties:
#服務名稱 spring.application.name=dubbo-consumer server.port=4001 #表示要訂閱服務的服務名,可以配置'*'代表訂閱所有服務(不推薦使用)。若需訂閱多應用,使用","分割。 dubbo.cloud.subscribed-services=dubbo-sample-provider #nacos spring.cloud.nacos.discovery.server-addr=localhost:8848 #禁止該服務注冊到Nacos服務列表中 spring.cloud.nacos.discovery.register-enabled=false
實現服務調用,新建HelloController.java類:
package com.zxy.dubbo_consumer.control; import com.zxy.dubbo_sample_api.IHelloService; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @DubboReference private IHelloService helloService; @GetMapping("/say") public String sayHello(){ return helloService.sayHello("Lily"); } }
注意:這里的@DubboReference注解是Dubbo的org.apache.dubbo.config.annotation.DubboReference,千萬不要引用錯誤。
手寫過RPC框架的同學,應該都知道,客戶端通過服務端的接口契約可以調用服務端的接口,其實是采用動態代理的方式,dubbo中默認采用javasist,大家不妨debug一下。@DubboReference作用就是將動態代理注入進來。
創建應用主類,即項目入口DubboConsumerApplication.java文件。如果使用SpringBoot自動創建項目該文件是自動創建的不用做任何修改。
package com.zxy.dubbo_consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DubboConsumerApplication { public static void main(String[] args) { SpringApplication.run(DubboConsumerApplication.class, args); } }
(4)測試:
啟動Nacoe、啟動服務提供項目dubbo-sample-provider、服務消費項目dubbo-consumer、確保接口契約項目已經添加到maven本地倉庫中。啟動完成后,我們可以訪問Nacos控制台的服務列表上已經注冊的以上服務。具體參照之前的步驟。
我們打開瀏覽器訪問:http://localhost:4001/say,可以看到頁面正常顯示Hello World:Lily!表示測試成功。
