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>

dubbo-provider-service 的application.yml裏添加配置

注:如果要在 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 #註冊中心地址,格式爲 註冊中心組件名://註冊中心訪問地址

創建實現類 EchoServiceImpl

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

相關文章