Spring Cloud 系列之 Dubbo RPC 通信


Dubbo 介紹

官網:http://dubbo.apache.org/zh-cn/

Github:https://github.com/apache/dubbo

2018 年 2 月 15 日,阿里巴巴的服務治理框架 dubbo 通過投票,順利成為 Apache 基金會孵化項目。

Apache Dubbo 是一款高性能、輕量級的開源 Java RPC 框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動注冊和發現。

Dubbo 架構

Dubbo 提供三個核心功能:基於接口的遠程調用、容錯和負載均衡,以及服務的自動注冊與發現。Dubbo 框架廣泛的在阿里巴巴內部使用,以及當當、去哪兒、網易考拉、滴滴等都在使用。

節點角色說明

節點 角色說明
Provider 暴露服務的服務提供方
Consumer 調用遠程服務的服務消費方
Registry 服務注冊與發現的注冊中心
Monitor 統計服務的調用次數和調用時間的監控中心
Container 服務運行容器

調用關系說明

  1. 服務容器負責啟動,加載,運行服務提供者。
  2. 服務提供者在啟動時,向注冊中心注冊自己提供的服務。
  3. 服務消費者在啟動時,向注冊中心訂閱自己所需的服務。
  4. 注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基於長連接推送變更數據給消費者。
  5. 服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。
  6. 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鍾發送一次統計數據到監控中心。

Dubbo 快速入門

我們先通過一個簡單的案例讓大家理解一下 Dubbo 的使用,然后基於 Spring Boot 和 Spring Cloud 環境整合 Dubbo。

Dubbo 采用全 Spring 配置方式,透明化接入應用,對應用沒有任何 API 侵入,只需用 Spring 加載 Dubbo 的配置即可。

依賴

JDK 1.6 以上和 Maven 3.0 以上,采用 Maven 多模塊聚合工程構建 api 模塊,provider 模塊以及 consumer 模塊。

聚合工程

項目結構如下圖,簡單介紹一下:

  • dubbo-api:服務接口
  • dubbo-provider:依賴服務接口,具體的業務實現,服務提供者
  • dubbo-coonsumer:依賴服務接口,遠程調用服務,服務消費者

依賴關系

dubbo-parent 的 pom.xml 依賴 apache dubbo。

<dependencies>
 <!-- apache dubbo 依賴 -->  <dependency>  <groupId>org.apache.dubbo</groupId>  <artifactId>dubbo</artifactId>  <version>2.7.4.1</version>  </dependency> </dependencies> 

dubbo-provider 和 dubbo-consumer 的 pom.xml 依賴 dubbo-api 服務接口。

<dependencies>
 <!-- dubbo-api 依賴 -->  <dependency>  <groupId>org.example</groupId>  <artifactId>dubbo-api</artifactId>  <version>1.0-SNAPSHOT</version>  </dependency> </dependencies> 

定義服務接口

dubbo-api 中編寫 HelloService.java

package org.example.service;
 /**  * Hello服務  */ public interface HelloService {   String sayHello(String name);  } 

定義服務提供者

在 provider 模塊中實現服務接口

dubbo-provider 中編寫 HelloServiceImpl.java

package org.example.service.impl;
 import org.example.service.HelloService;  /**  * 服務實現  */ public class HelloServiceImpl implements HelloService {   public String sayHello(String name) {  return "hello " + name;  }  } 

配置服務提供者

dubbo-provider.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"  xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  http://dubbo.apache.org/schema/dubbo  http://dubbo.apache.org/schema/dubbo/dubbo.xsd">   <!-- 提供方應用信息,用於計算依賴關系 -->  <dubbo:application name="hello-world-app"/>   <!-- 使用 multicast 廣播注冊中心暴露服務地址 -->  <dubbo:registry address="multicast://224.5.6.7:1234"/>   <!-- 用 dubbo 協議在 20880 端口暴露服務 -->  <dubbo:protocol name="dubbo" port="20880"/>   <!-- 聲明需要暴露的服務接口 -->  <dubbo:service interface="org.example.service.HelloService" ref="helloService"/>   <!-- 和本地 bean 一樣實現服務 -->  <bean id="helloService" class="org.example.service.impl.HelloServiceImpl"/>  </beans> 

加載 Spring 配置啟動服務

package org.example;
 import org.springframework.context.support.ClassPathXmlApplicationContext;  /**  * 發布服務  */ public class Provider {   public static void main(String[] args) throws Exception {  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:dubbo-provider.xml");  context.start();  System.out.println("服務注冊成功!");  System.in.read(); // 按任意鍵退出  }  } 

定義服務消費者

通過 Spring 配置引用遠程服務

dubbo-consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"  xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  http://dubbo.apache.org/schema/dubbo  http://dubbo.apache.org/schema/dubbo/dubbo.xsd">   <!-- 消費方應用名,用於計算依賴關系,不是匹配條件,不要與提供方一樣 -->  <dubbo:application name="consumer-of-helloworld-app" />   <!-- 使用 multicast 廣播注冊中心暴露發現服務地址 -->  <dubbo:registry address="multicast://224.5.6.7:1234" />   <!-- 生成遠程服務代理,可以和本地 bean 一樣使用 helloService -->  <dubbo:reference id="helloService" interface="org.example.service.HelloService" />  </beans> 

加載 Spring 配置並調用遠程服務

package org.example;
 import org.example.service.HelloService; import org.springframework.context.support.ClassPathXmlApplicationContext;  /**  * 調用遠程服務  */ public class Consumer {  public static void main(String[] args) throws Exception {  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:dubbo-consumer.xml");  context.start();  HelloService helloService = (HelloService) context.getBean("helloService"); // 獲取遠程服務代理  String result = helloService.sayHello("world"); // 執行遠程方法  System.out.println(result); // 顯示調用結果  } } 

Dubbo 常用標簽

  • dubbo:application:應用程序名稱
  • dubbo:registry:連接注冊中心信息(配置注冊中心)
  • dubbo:protocol:服務提供者注冊服務采用的協議
    • Dubbo 協議,默認
    • RMI 協議
    • Hessian 協議
    • HTTP 協議
    • WebService 協議
    • Thrift 協議
    • Memcached 協議
    • Redis 協議
    • Rest 協議(RESTful)
    • Grpc 協議
    • 更多協議信息請參考:http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html
  • dubbo:service:聲明需要暴露的服務接口
  • dubbo:reference:配置訂閱的服務(生成遠程服務代理)

更多配置信息請參考:http://dubbo.apache.org/zh-cn/docs/user/references/xml/introduction.html

注冊中心

注冊中心我們已經學習了不少,例如:ZooKeeper、Eureka、Consul、Nacos 等等,注冊中心可以更高效的管理系統的服務:比如服務接口的發布、自動剔除無效的服務、自動恢復服務等。

Dubbo 支持五種注冊中心:Multicast、Nacos(推薦)、ZooKeeper(推薦) 、Redis、Simple。本文重點介紹前兩個,更多注冊中心的信息請參考:http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html

Multicast 注冊中心

Multicast 注冊中心不需要啟動任何中心節點,只要廣播地址一樣,就可以互相發現。

  1. 提供方啟動時廣播自己的地址
  2. 消費方啟動時廣播訂閱請求
  3. 提供方收到訂閱請求時,單播自己的地址給訂閱者,如果設置了 unicast=false,則廣播給訂閱者
  4. 消費方收到提供方地址時,連接該地址進行 RPC 調用。

組播受網絡結構限制,只適合小規模應用或開發階段使用。組播地址段: 224.0.0.0 - 239.255.255.255

配置

<dubbo:registry address="multicast://224.5.6.7:1234" />

<dubbo:registry protocol="multicast" address="224.5.6.7:1234" />

為了減少廣播量,Dubbo 缺省使用單播發送提供者地址信息給消費者,如果一個機器上同時啟了多個消費者進程,消費者需聲明 unicast=false,否則只會有一個消費者能收到消息。

當服務者和消費者運行在同一台機器上,消費者同樣需要聲明unicast=false,否則消費者無法收到消息,導致 No provider available for the service 異常。

<dubbo:registry address="multicast://224.5.6.7:1234?unicast=false" />

<dubbo:registry protocol="multicast" address="224.5.6.7:1234">
 <dubbo:parameter key="unicast" value="false" /> </dubbo:registry> 

zookeeper 注冊中心

Apache ZooKeeper 是一個開放源碼的分布式應用程序協調組件,是 Hadoop 和 Hbase 的重要組件。它是一個為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。適合作為 Dubbo 服務的注冊中心,工業強度較高,可用於生產環境,推薦使用。

在微服務項目開發中 ZooKeeper 主要的角色是當做服務注冊中心存在,我們將編寫好的服務注冊至 ZooKeeper 即可。

流程說明:

  • 服務提供者啟動時: 向 /dubbo/com.foo.BarService/providers 目錄下寫入自己的 URL 地址。
  • 服務消費者啟動時: 訂閱 /dubbo/com.foo.BarService/providers 目錄下的提供者 URL 地址。並向 /dubbo/com.foo.BarService/consumers 目錄下寫入自己的 URL 地址。
  • 監控中心啟動時: 訂閱 /dubbo/com.foo.BarService 目錄下的所有提供者和消費者 URL 地址。

支持以下功能:

  • 當提供者出現斷電等異常停機時,注冊中心能自動刪除提供者信息;
  • 當注冊中心重啟時,能自動恢復注冊數據,以及訂閱請求;
  • 當會話過期時,能自動恢復注冊數據,以及訂閱請求;
  • 當設置 <dubbo:registry check="false" /> 時,記錄失敗注冊和訂閱請求,后台定時重試;
  • 可通過 <dubbo:registry username="admin" password="1234" /> 設置 zookeeper 登錄信息;
  • 可通過 <dubbo:registry group="dubbo" /> 設置 zookeeper 的根節點,不配置將使用默認的根節點;
  • 支持 * 號通配符 <dubbo:reference group="*" version="*" />,可訂閱服務的所有分組和所有版本的提供者。

作為 Dubbo 的老牌黃金搭檔 ZooKeeper,我們在單獨講解 Dubbo 時已經給大家分享過如何使用了,本文系 Spring Cloud Alibaba 系列文章,重點對象是 Nacos,所以 ZooKeeper 這里就不過多贅述了。

Nacos 注冊中心

Nacos 是 Alibaba 公司推出的開源工具,用於實現分布式系統的服務發現與配置管理。Nacos 是 Dubbo 生態系統中重要的注冊中心實現,其中 dubbo-registry-nacos 則是 Dubbo 融合 Nacos 注冊中心的實現,推薦使用。

Nacos 官網:https://nacos.io/zh-cn/

Github:https://github.com/alibaba/nacos

預備工作

當您將 Nacos 整合到您的 Dubbo 工程之前,請確保后台已經啟動 Nacos 服務。關於 Nacos 的安裝和其他詳細內容可參考我之前的文章 Spring Cloud 系列之 Alibaba Nacos 注冊中心

快速上手

Dubbo 融合 Nacos 成為注冊中心的操作步驟非常簡單,大致步驟可分為“增加 Maven 依賴”和“配置注冊中心“。

依賴

核心依賴主要是 dubbo-registry-nacosnacos-client

<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
<dependency>  <groupId>org.apache.dubbo</groupId>  <artifactId>dubbo-registry-nacos</artifactId>  <version>2.7.4.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client --> <dependency>  <groupId>com.alibaba.nacos</groupId>  <artifactId>nacos-client</artifactId>  <version>1.3.0</version> </dependency> 

配置注冊中心

服務提供者和服務消費者只需要調整 address 屬性配置即可。

單機配置:

<!-- 使用 Nacos 注冊中心,單機版 -->
<dubbo:registry address="nacos://127.0.0.1:8848"/> <!-- 或 --> <dubbo:registry protocol="nacos" address="127.0.0.1:2181"/> 

或:

dubbo.register.address=nacos://192.168.10.101:8848

或:

dubbo.register.protocol=nacos
dubbo.register.address=192.168.10.101:8848

集群配置:

<!-- 使用 Nacos 注冊中心,集群版 -->
<dubbo:registry address="nacos://192.168.10.101:2181?backup=192.168.10.102:2181,192.168.10.103:2181"/> <!-- 或 --> <dubbo:registry protocol="nacos" address="192.168.10.101:2181,192.168.10.102:2181,192.168.10.103:2181"/> 

或:

dubbo.register.address=nacos://192.168.10.101:8848

或:

dubbo.register.protocol=nacos
dubbo.register.address=192.168.10.101:8848,192.168.10.102:8848,192.168.10.103:8848

隨后,重啟您的 Dubbo 應用,Dubbo 的服務提供和消費信息在 Nacos 控制台中即可顯示。

Spring Cloud Alibaba Nacos 整合 Dubbo

之前的文章中,無論我們學習 Eureka、Consul 還是 Nacos,負責服務間通信的功能都是由 Ribbon 來完成的,接下來我們使用 Dubbo 來替換 Ribbon。

聚合工程

dubbo-demo 聚合工程。SpringBoot 2.3.0.RELEASESpring Cloud Hoxton.SR5

項目結構如下圖,簡單介紹一下:

  • service-api:服務接口
  • product-service:商品服務,服務提供者,提供了 /product/list 接口
  • order-service:訂單服務,服務消費者,遠程調用商品服務

依賴關系

dubbo-demo 的 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.example</groupId>  <!-- 項目模塊名稱 -->  <artifactId>dubbo-demo</artifactId>  <packaging>pom</packaging>  <!-- 項目版本名稱 快照版本SNAPSHOT、正式版本RELEASE -->  <version>1.0-SNAPSHOT</version>  <modules>  <module>service-api</module>  <module>product-service</module>  <module>order-service</module>  </modules>   <!-- 繼承 spring-boot-starter-parent 依賴 -->  <!-- 使用繼承方式,實現復用,符合繼承的都可以被使用 -->  <parent>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-parent</artifactId>  <version>2.3.0.RELEASE</version>  </parent>   <!--  集中定義依賴組件版本號,但不引入,  在子工程中用到聲明的依賴時,可以不加依賴的版本號,  這樣可以統一管理工程中用到的依賴版本  -->  <properties>  <!-- Spring Cloud Hoxton.SR5 依賴 -->  <spring-cloud.version>Hoxton.SR5</spring-cloud.version>  <!-- spring cloud alibaba 依賴 -->  <spring-cloud-alibaba.version>2.1.0.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>  </project> 

service-api 的 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">  <parent>  <artifactId>dubbo-demo</artifactId>  <groupId>com.example</groupId>  <version>1.0-SNAPSHOT</version>  </parent>  <modelVersion>4.0.0</modelVersion>   <artifactId>service-api</artifactId>   <dependencies>  <!-- lombok 依賴 -->  <dependency>  <groupId>org.projectlombok</groupId>  <artifactId>lombok</artifactId>  </dependency>  </dependencies>  </project> 

product-service 需要依賴 Nacos 和 Dubbo 的依賴,還有 service-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">   <!-- 繼承父依賴 -->  <parent>  <artifactId>dubbo-demo</artifactId>  <groupId>com.example</groupId>  <version>1.0-SNAPSHOT</version>  </parent>  <modelVersion>4.0.0</modelVersion>   <artifactId>product-service</artifactId>   <!-- 項目依賴 -->  <dependencies>  <!-- spring cloud alibaba nacos discovery 依賴 -->  <dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>  </dependency>  <!-- spring cloud alibaba dubbo 依賴 -->  <dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-alibaba-dubbo</artifactId>  </dependency>  <!-- spring boot web 依賴 -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  </dependency>  <!-- service-api 依賴 -->  <dependency>  <groupId>com.example</groupId>  <artifactId>service-api</artifactId>  <version>1.0-SNAPSHOT</version>  </dependency>   <!-- spring boot test 依賴 -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-test</artifactId>  <scope>test</scope>  <exclusions>  <exclusion>  <groupId>org.junit.vintage</groupId>  <artifactId>junit-vintage-engine</artifactId>  </exclusion>  </exclusions>  </dependency>  </dependencies>  </project> 

order-service 需要依賴 Nacos 和 Dubbo 的依賴,還有 service-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">   <!-- 繼承父依賴 -->  <parent>  <artifactId>dubbo-demo</artifactId>  <groupId>com.example</groupId>  <version>1.0-SNAPSHOT</version>  </parent>  <modelVersion>4.0.0</modelVersion>   <artifactId>order-service</artifactId>   <!-- 項目依賴 -->  <dependencies>  <!-- spring cloud alibaba nacos discovery 依賴 -->  <dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>  </dependency>  <!-- spring cloud alibaba dubbo 依賴 -->  <dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-alibaba-dubbo</artifactId>  </dependency>  <!-- spring boot web 依賴 -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  </dependency>  <!-- service-api 依賴 -->  <dependency>  <groupId>com.example</groupId>  <artifactId>service-api</artifactId>  <version>1.0-SNAPSHOT</version>  </dependency>   <!-- spring boot test 依賴 -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-test</artifactId>  <scope>test</scope>  <exclusions>  <exclusion>  <groupId>org.junit.vintage</groupId>  <artifactId>junit-vintage-engine</artifactId>  </exclusion>  </exclusions>  </dependency>  </dependencies>  </project> 

定義服務接口

我們在 service-api 模塊中定義實體類和服務接口信息。

實體類

Product.java

package com.example.product.pojo;
 import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;  import java.io.Serializable;  @Data @NoArgsConstructor @AllArgsConstructor public class Product implements Serializable {   private Integer id;  private String productName;  private Integer productNum;  private Double productPrice;  } 

Order.java

package com.example.product.pojo;
 import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;  import java.io.Serializable; import java.util.List;  @Data @NoArgsConstructor @AllArgsConstructor public class Order implements Serializable {   private Integer id;  private String orderNo;  private String orderAddress;  private Double totalPrice;  private List<Product> productList;  } 

服務接口

package com.example.product.service;
 import com.example.product.pojo.Product;  import java.util.List;  /**  * 商品服務  */ public interface ProductService {   /**  * 查詢商品列表  *  * @return  */  List<Product> selectProductList();  } 

定義服務提供者

配置文件

配置文件需要配置 Nacos 注冊中心和 Dubbo 相關信息,核心配置如下:

server:
 port: 7070 # 端口  spring:  application:  name: product-service # 應用名稱  # 配置 Nacos 注冊中心  cloud:  nacos:  discovery:  enabled: true # 如果不想使用 Nacos 進行服務注冊和發現,設置為 false 即可  server-addr: 127.0.0.1:8848 # Nacos 服務器地址,單機版  # Dubbo dubbo:  # 提供方應用信息,用於計算依賴關系  application:  name: product-service  # 使用 nacos 注冊中心暴露服務地址  registry:  protocol: nacos  address: spring-cloud://localhost  # 用 dubbo 協議在 20880 端口暴露服務  protocol:  name: dubbo  port: 20880  # 掃描需要暴露的服務,可以被 @EnableDubbo 注解替代  #scan:  # base-packages: com.example.service 

服務提供者

product-service 的 ProductServiceImpl.java

package com.example.service.impl;
 import com.example.product.pojo.Product; import com.example.product.service.ProductService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.Service;  import java.util.Arrays; import java.util.List;  /**  * 商品服務  * timeout 調用該服務的超時時間  * version 為版本號  * group 為分組  * interface、group、version 三者確定一個服務  */ @Slf4j @Service(timeout = 5000, version = "1.0", group = "product-service") public class ProductServiceImpl implements ProductService {   /**  * 查詢商品列表  *  * @return  */  @Override  public List<Product> selectProductList() {  log.info("商品服務查詢商品信息...");  return Arrays.asList(  new Product(1, "華為手機", 1, 5800D),  new Product(2, "聯想筆記本", 1, 6888D),  new Product(3, "小米平板", 5, 2020D)  );  }  } 

值得注意的是 @Service 注解不是 Spring 的注解而是 Dubbo 的注釋:

啟動類

啟動類通過 @EnableDubbo 注解掃描需要暴露的服務,如果配置文件中配置了該選項,那么這里可以省略。

package com.example;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;  // 掃描需要暴露的服務 @EnableDubbo(scanBasePackages = "com.example.service") // 開啟 @EnableDiscoveryClient 注解,當前版本默認會開啟該注解 //@EnableDiscoveryClient @SpringBootApplication public class ProductServiceApplication {   public static void main(String[] args) {  SpringApplication.run(ProductServiceApplication.class, args);  }  } 

定義服務消費者

配置文件

配置文件需要配置 Nacos 注冊中心和 Dubbo 相關信息,核心配置如下:

server:
 port: 9090 # 端口  spring:  application:  name: order-service # 應用名稱  # 配置 Nacos 注冊中心  cloud:  nacos:  discovery:  enabled: true # 如果不想使用 Nacos 進行服務注冊和發現,設置為 false 即可  server-addr: 127.0.0.1:8848 # Nacos 服務器地址,單機版  # Dubbo dubbo:  # 消費方應用名,用於計算依賴關系,不是匹配條件,不要與提供方一樣  application:  name: order-service  # 發現 nacos 注冊中心暴露的服務  registry:  protocol: nacos  address: spring-cloud://localhost  cloud:  subscribed-services: product-service # 訂閱服務,遠程調用的服務名稱 

服務消費者

order-service 的 OrderServiceImpl.java

package com.example.service.impl;
 import com.example.product.pojo.Order; import com.example.product.service.ProductService; import com.example.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.Reference; import org.springframework.stereotype.Service;  @Slf4j @Service public class OrderServiceImpl implements OrderService {   // dubbo 提供了 @Reference 注解,可替換 @Autowired 注解,用於引入遠程服務  // 如果注冊服務時設置了版本及分組信息,調用遠程服務時也要設置對應的版本及分組信息  @Reference(timeout = 5000, version = "1.0", group = "product-service")  private ProductService productService;   /**  * 根據主鍵查詢訂單  *  * @param id  * @return  */  @Override  public Order selectOrderById(Integer id) {  log.info("訂單服務查詢訂單信息...");  return new Order(id, "order-001", "中國", 22788D,  productService.selectProductList());  }  } 

啟動類

package com.example;
 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;  // 開啟 @EnableDiscoveryClient 注解,當前版本默認會開啟該注解 //@EnableDiscoveryClient @SpringBootApplication public class OrderServiceApplication {   public static void main(String[] args) {  SpringApplication.run(OrderServiceApplication.class, args);  }  } 

測試

先啟動 Nacos 服務器,然后啟動服務提供者 product-service,訪問:http://localhost:8848/nacos/ 控制台顯示如下:

然后啟動服務消費者,控制台顯示如下:

訂單服務調用遠程商品服務,結果如下:

Dubbo 負載均衡

在集群負載均衡時,Dubbo 提供了多種均衡策略,缺省為 random 隨機調用,也可以自行擴展負載均衡策略。

負載均衡策略

Random LoadBalance

  • 隨機,按權重設置隨機概率。
  • 在一個截面上碰撞的概率高,但調用量越大分布越均勻,而且按概率使用權重后也比較均勻,有利於動態調整提供者權重。

RoundRobin LoadBalance

  • 輪詢,按公約后的權重設置輪詢比率。
  • 存在慢的提供者累積請求的問題,比如:第二台機器很慢,但沒掛,當請求調到第二台時就卡在那,久而久之,所有請求都卡在調到第二台上。

LeastActive LoadBalance

  • 最少活躍調用數,ping 值(延遲低)的調用,相同延遲的情況下隨機。
  • 使慢的提供者收到更少請求,因為越慢的提供者的調用前后計數差會越大。

ConsistentHash LoadBalance

  • 一致性 Hash,相同參數的請求總是發到同一提供者。
  • 當某一台提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。
  • 算法參見:http://en.wikipedia.org/wiki/Consistent_hashing
  • 缺省只對第一個參數 Hash,如果要修改,請配置 <dubbo:parameter key="hash.arguments" value="0,1" />
  • 缺省用 160 份虛擬節點,如果要修改,請配置 <dubbo:parameter key="hash.nodes" value="320" />

配置

一般在項目中不會在代碼層面指定權重,而是通過監控中心(dubbo-admin)對服務動態的指定權重,官方文檔:http://dubbo.apache.org/zh-cn/docs/admin/introduction.html

xml

服務端服務級別

<dubbo:service interface="..." loadbalance="roundrobin" weight="100" />

客戶端服務級別

<dubbo:reference interface="..." loadbalance="roundrobin" />

服務端方法級別

<dubbo:service interface="..." weight="100">
 <dubbo:method name="..." loadbalance="roundrobin"/> </dubbo:service> 

客戶端方法級別

<dubbo:reference interface="...">
 <dubbo:method name="..." loadbalance="roundrobin"/> </dubbo:reference> 

yaml

dubbo:
 provider:  loadbalance: roundrobin  weight: 100  consumer:  loadbalance: roundrobin 

注解

@Service(loadbalance = "roundrobin", weight = 100)
@Reference(loadbalance = "roundrobin") 

至此 Dubbo RPC 通信所有的知識點就講解結束了。

本文采用 知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議

大家可以通過 分類 查看更多關於 Spring Cloud 的文章。

🤗 您的點贊轉發是對我最大的支持。

📢 掃碼關注 哈嘍沃德先生「文檔 + 視頻」每篇文章都配有專門視頻講解,學習更輕松噢 ~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM