Dubbo簡介
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動注冊和發現。致力於提高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。
節點 | 角色說明 |
---|---|
Provider |
暴露服務的服務提供方 |
Consumer |
調用遠程服務的服務消費方 |
Registry |
服務注冊與發現的注冊中心 |
Monitor |
統計服務的調用次數和調用時間的監控中心 |
Container |
服務運行容器 |
功能特點:
-
面向接口代理的高性能RPC調用:
提供高性能的基於代理的遠程調用能力,服務以接口為粒度,為開發者屏蔽遠程調用底層細節。
-
智能負載均衡:
內置多種負載均衡策略,智能感知下游節點健康狀況,顯著減少調用延遲,提高系統吞吐量。
-
服務自動注冊與發現:
支持多種注冊中心服務,服務實例上下線實時感知。
-
高度可擴展能力:
遵循微內核+插件的設計原則,所有核心能力如Protocol、Transport、Serialization被設計為擴展點,平等對待內置實現和第三方實現。
-
運行期流量調度:
內置條件、腳本等路由策略,通過配置不同的路由規則,輕松實現灰度發布,同機房優先等功能。
-
可視化的服務治理與運維:
提供豐富服務治理、運維工具:隨時查詢服務元數據、服務健康狀態及調用統計,實時下發路由策略、調整配置參數。
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 Alibaba 整合 Dubbo
創建ApacheDubbo總工程, 在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.gofy</groupId> <artifactId>ApacheDubbo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.8.RELEASE</version> </parent> <modules> <module>dubbo-provider</module> <module>dubbo-consumer</module> </modules> <properties> <!-- Environment Settings --> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>Greenwich.SR3</spring-cloud.version> <spring-cloud-alibaba.version>0.2.1.RELEASE</spring-cloud-alibaba.version> <dubbo.version>2.7.6</dubbo.version> <dubbo-spring.version>2.7.6</dubbo-spring.version> <dubbo-actuator.version>2.7.6</dubbo-actuator.version> <dubbo-kryo.version>2.7.6</dubbo-kryo.version> <dubbo-nacos.version>2.7.6</dubbo-nacos.version> <dubbo-nacos-config.version>2.1.0.RELEASE</dubbo-nacos-config.version> <spring-context-support.version>1.0.6</spring-context-support.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Apache Dubbo --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-actuator</artifactId> <version>${dubbo-actuator.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo-spring.version}</version> </dependency> <!-- 使用kryo序列化/反序列化工具, 提高項目性能 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-serialization-kryo</artifactId> <version>${dubbo-kryo.version}</version> </dependency> <!-- Spring Cloud Alibaba --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>${dubbo-nacos.version}</version> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>${dubbo-nacos-config.version}</version> </dependency> <dependency> <groupId>com.alibaba.spring</groupId> <artifactId>spring-context-support</artifactId> <version>${spring-context-support.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <!-- Compiler 插件, 設定 JDK 版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <showWarnings>true</showWarnings> </configuration> </plugin> </plugins> <!-- 資源文件配置 --> <resources> <resource> <directory>src/main/java</directory> <excludes> <exclude>**/*.java</exclude> </excludes> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> </build> </project>
服務提供者
在Dubbo RPC框架中, 服務提供者的接口類和實現類應該分開為倆個模塊, 所以我們應該在服務提供者下創建兩個子模塊, 分別為 接口模塊dubbo-provider-api 和 實現模塊dubbo-provider-service
在總工程 ApacheDubbo下創建dubbo-provider模塊, 添加服務提供者的統一依賴
<?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> <parent> <artifactId>ApacheDubbo</artifactId> <groupId>com.gofy</groupId> <version>1.0-SNAPSHOT</version> </parent> <groupId>com.gofy</groupId> <artifactId>dubbo-provider</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>dubbo-provider-api</module> <module>dubbo-provider-service</module> </modules> </project>
-
在dubbo-provider下創建dubbo-provider-api子模塊, 並添加依賴
<?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> <parent> <artifactId>dubbo-provider</artifactId> <groupId>com.gofy</groupId> <version>1.0-SNAPSHOT</version> </parent> <groupId>com.gofy</groupId> <artifactId>dubbo-provider-api</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> </project>
創建接口類 EchoService
package com.gofy.dubbo.api; public interface EchoService { String echo(String s); }
-
在dubbo-provider下創建dubbo-provider-service子模塊, 並添加依賴
導入接口模塊失敗原因: 一般是總工程的統一依賴出了問題, 可以查看本地maven倉庫的中總工程導入的依賴的包有沒有缺失文件. 我之前失敗原因就是 spring-cloud-dependencies 包出了問題, Greenwich.SR5版本下載一直缺失文件, 改為Greenwich.SR3就好了.
<?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> <parent> <artifactId>dubbo-provider</artifactId> <groupId>com.gofy</groupId> <version>1.0-SNAPSHOT</version> </parent> <groupId>com.gofy</groupId> <artifactId>dubbo-provider-service</artifactId> <packaging>jar</packaging> <dependencies> <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.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-serialization-kryo</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo-registry-nacos</artifactId> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> </dependency> <dependency> <groupId>com.alibaba.spring</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- 導入接口模塊 --> <dependency> <groupId>com.gofy</groupId> <artifactId>dubbo-provider-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.gofy.dubbo.ProviderApplication</mainClass> </configuration> </plugin> </plugins> </build> </project>
在
注:如果要在 SpringClou Alibaba+Dubbo 中使用nacos動態配置,操作與之前naocs動態配置的操作一樣
spring:
application:
name: dubbo-provider
main:
allow-bean-definition-overriding: true # 解決bean重復定義,設置為true時,后定義的bean會覆蓋之前定義的相同名稱的bean
dubbo:
scan:
base-packages: com.gofy.dubbo.service # 實現類所在的包
protocol:
name: dubbo
port: -1 # 端口為-1時,即是讓dubbo自動分配端口
serialization: kryo # 使用kryo序列化/反序列化工具
registry:
address: nacos://192.168.11.132:8848 #注冊中心地址,格式為 注冊中心組件名://注冊中心訪問地址
package com.gofy.dubbo.service; import com.gofy.dubbo.api.EchoService; import org.apache.dubbo.config.annotation.Service; import org.springframework.beans.factory.annotation.Value; @Service(version = "1.0.0") //服務版本號 public class EchoServiceImpl implements EchoService { @Override public String echo(String s) { return "Hello Dubbo "+s; } }
創建啟動類 ProviderApplication
@SpringBootApplication public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
服務消費者
在總工程 ApacheDubbo下創建服務消費者 dubbo-consumer, 並添加依賴
<?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> <parent> <artifactId>ApacheDubbo</artifactId> <groupId>com.gofy</groupId> <version>1.0-SNAPSHOT</version> </parent> <groupId>com.gofy</groupId> <artifactId>dubbo-consumer</artifactId> <packaging>jar</packaging> <dependencies> <!-- SpringBoot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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-starter-actuator</artifactId> </dependency> <!-- Dubbo --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-actuator</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-serialization-kryo</artifactId> </dependency> <!-- Spring Cloud Alibaba --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo-registry-nacos</artifactId> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> </dependency> <dependency> <groupId>com.alibaba.spring</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- 導入接口模塊 --> <dependency> <groupId>com.gofy</groupId> <artifactId>dubbo-provider-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.gofy.dubbo.ConsumerApplication</mainClass> </configuration> </plugin> </plugins> </build> </project>
在dubbo-consumer的application.yml里添加配置
server:
port: 8080
spring:
application:
name: dubbo-consumer
main:
allow-bean-definition-overriding: true
dubbo:
scan:
base-packages: com.gofy.dubbo.controller #controller類所在包
protocol:
name: dubbo
port: -1
serialization: kryo
registry:
address: nacos://192.168.11.132:8848
endpoints:
dubbo:
enabled: true #允許暴露dubbo分配的端點
management:
health: #健康檢查
dubbo:
status:
defaults: memory
extras: threadpool
endpoints: #暴露所有web端點
web:
exposure:
include: "*"
創建controller類 EchoController
package com.gofy.dubbo.controller; import com.gofy.dubbo.api.EchoService; import org.apache.dubbo.config.annotation.Reference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class EchoController { @Reference(version = "1.0.0") //通過服務的版本號注入 EchoService echoService; @GetMapping("/echo/{s}") public String echo(@PathVariable("s")String s){ return echoService.echo(s); } }
創建啟動類 ConsumerApplication
@SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
訪問測試
訪問nacos注冊中心,查看已注冊服務
訪問 localhost:8080/echo/hi , 成功獲取到服務提供者返回的信息
Dubbo負載均衡
當我們對內使用Dubbo的RPC通信,不再使用RestTemplate或feign的 HTTP通信時,我們要怎么使用負載均衡呢?
在 Dubbo 中,也有負載均衡的概念和相應的實現。Dubbo 需要對服務消費者的調用請求進行分配,避免少數服務提供者負載過大。服務提供者負載過大,會導致部分請求超時。因此將負載均衡到每個服務提供者上,是非常必要的。Dubbo 提供了4種負載均衡實現,分別是基於權重隨機算法的 RandomLoadBalance、基於最少活躍調用數算法的 LeastActiveLoadBalance、基於 hash 一致性的 ConsistentHashLoadBalance,以及基於加權輪詢算法的 RoundRobinLoadBalance。
源碼分析
Dubbo負載均衡的源碼在 org.apache.dubbo:dubbo下的org.apache.dubbo.rpc.cluster.loadbalance
通過源碼可以發現4個負載均衡策略的實現類都繼承了AbstractLoadBalance抽象類,而AbstractLoadBalance實現了LoadBalance接口。
再來看看LoadBalance接口,可以知道duboo是通過 loadbalance屬性來適配負載均衡接口的實現類,且默認值為 random權重隨機。
@SPI("random") public interface LoadBalance { @Adaptive({"loadbalance"}) <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException; }
所以,我們只要在@Reference注解里添加 loadbalance屬性,就可以選擇dubbo的負載均衡策略了
loadbalance屬性值為負載均衡實現類的 NAME屬性,分別是:
random 、roundrobin 、leastactive 、consistenthash
@Reference(version = "1.0.0", loadbalance = "roundrobin")
EchoService echoService;
負載均衡策略實現類的詳細源碼分析,dubbo官方文檔里講解得非常好,就不多轉述了
翻譯 朗讀 復制 正在查詢,請稍候…… 重試 朗讀 復制 復制 朗讀 復制 via 谷歌翻譯(國內)譯
翻譯 朗讀 復制 正在查詢,請稍候…… 重試 朗讀 復制 復制 朗讀 復制 via 谷歌翻譯(國內) 譯