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 谷歌翻譯(國內) 譯