(一)Dubbo快速入門教程(詳細+例子)


1、介紹

Dubbo官方文檔:https://dubbo.apache.org/zh

目前Dubbo最新的是Dubbo3。本文使用的是 2.7.3 (推薦)

Dubbo3 格式的 Provider 地址不能被 Dubbo2 的 Consumer 識別到,反之 Dubbo2 的消費者也不能訂閱到 Dubbo3 Provider。

這里的架構和使用都是基於Dubbo2.7 版本,Dubbo2(2.7以下)和Dubbo3兩個版本的注解有區別。

Registry是注冊中心,用於發現服務者和消費者。

注冊中心可以選擇 zookeeper、consul、nacos,推薦使用zookeeper。

dubboRPC通信的原理:

dubbo和springCloud的區別:

2、架構

Dubbo三大組件:

  • 注冊中心。協調 Consumer 與 Provider 之間的地址注冊與發現
  • 配置中心。
    • 存儲 Dubbo 啟動階段的全局配置,保證配置的跨環境共享與全局一致性
    • 負責服務治理規則(路由規則、動態配置等)的存儲與推送。
  • 元數據中心。
    • 接收 Provider 上報的服務接口元數據,為 Admin 等控制台提供運維能力(如服務測試、接口文檔等)
    • 作為服務發現機制的補充,提供額外的接口/方法級別配置信息的同步能力,相當於注冊中心的額外擴展

以上三個中心並不是運行 Dubbo 的必要條件,用戶完全可以根據自身業務情況決定只啟用其中一個或多個,以達到簡化部署的目的。

通常情況下,所有用戶都會以獨立的注冊中心 開始 Dubbo 服務開發,而配置中心、元數據中心則會在微服務演進的過程中逐步的按需被引入進來。

3、使用

依賴:(推薦使用2.7.13版本)。

spring集成dubbo:

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.7.13</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-zookeeper</artifactId>
    <version>2.7.13</version>
</dependency>

springboot與dubbo集成:

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.13</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-zookeeper</artifactId>
    <version>2.7.13</version>
</dependency>

3.1、spring.xml配置

1、服務端

在服務提供方實現接口(對服務消費方隱藏實現):

spring-provider.xml :

<!--注意:配置集群的情況下需要同一集群的name值相同-->
<dubbo:application name="demo-provider" />
<!-- 使用zookeeper注冊中心暴露服務地址 --> 
<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181" />
<!--實際項目中使用properties文件的形式定義zookeeper的地址 -->
<!-- <dubbo:registry protocol="zookeeper" address="${zookeeper.address}"  check="false" file="dubbo.properties" /> -->


<dubbo:provider token="true" />
<!-- beanId -->
<bean id="demoService" class="org.apache.dubbo.samples.basic.impl.DemoServiceImpl"/>

<!--用 Spring 配置聲明暴露服務,ref="demoService" 是 beanId,必填 -->
<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService" />
 <!--使用dubbo協議,聲明服務的端口-->
<dubbo:protocol name="dubbo" port="20898"/>

一般來說,我們會把 beanId 交給 spring 去管理只需要在 xml 里面聲明掃描包,然后使用 @Service 聲明實現類 即可:

<context:component-scan base-package="org.apache.dubbo.samples.basic.impl"/>

2、客戶端

spring-consumer.xml:

<dubbo:application name="demo-consumer"/>

<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
<!-- 服務方引用的beanId -->
<dubbo:reference id="demoService" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService"/>

3.2、springboot配置

1、服務端

上面例子的 spring-provider.xml 換成 properties 文件的寫法是這樣的:

# 應用名
dubbo.application.name=demo-provider
# 注冊中心地址
dubbo.registry.address=zookeeper://localhost:2181
# 調用協議地址
dubbo.protocol.name=dubbo
dubbo.protocol.port=28080
#開啟包掃描,可替代 @EnableDubbo 注解
#dubbo.scan.base-packages=com.meizu.quickgame

開啟基於注解的dubbo功能(主要是包掃描@DubboComponentScan):

// 開啟基於注解的dubbo功能(主要是包掃描@DubboComponentScan)
// 也可以在配置文件中使用dubbo.scan.base-package來替代@EnableDubbo
@EnableDubbo(scanBasePackages = {"com.meizu.quickgame"})
@SpringBootApplication
public class UserServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceProviderApplication.class, args);
    }
}

2、客戶端

# 應用名
dubbo.application.name=demo-consumer
# 注冊中心地址
dubbo.registry.address=zookeeper://localhost:2181
dubbo.consumer.timeout=1000

使用例子1:

dubbo和spring可以完美結合,只需要在spring配置文件聲明即可。

provider:

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml");
        context.start();
        new CountDownLatch(1).await();
    }

consumer:

public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml");
        context.start();
        DemoService demoService = (DemoService) context.getBean("demoService");
        String hello = demoService.sayHello("world");
}

使用例子2:

這里展示注解的方式,需要聲明@EnableDubbo

provider:

@DubboService(version = "1.0.0")
public class UserServiceImpl implements UserService{
    
}

consumer:

@DubboReference(version = "*", protocol = "dubbo,hessian", loadbalance = "random" )
private UserService userService;

4、其他

4.1、負載均衡:

xml:

服務端級別:

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService" loadbalance="roundrobin" timeout="5000"/>

服務端方法級別:

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService" timeout="5000">
	<dubbo:method name="sayHello" loadbalance="roundrobin"/>
</dubbo:service>

客戶端級別:

<dubbo:reference id="demoService" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService" loadbalance="roundrobin"/>

客戶端方法級別:

<dubbo:reference id="demoService" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService">
	<dubbo:method name="sayHello" loadbalance="roundrobin"/>
</dubbo:reference>

當多個provider注冊到zk,consumer會選擇指定的負載均衡算法自動請求,遇到上線或者下線會重新計算。

常見有四種負載均衡:

  • random

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

  • roundRobin (默認)

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

  • leastActive

最少活躍調用數,相同活躍數的隨機,活躍數指調用前后計數差。
使慢的提供者收到更少請求,因為越慢的提供者的調用前后計數差會越大。

  • consistentHash

一致性Hash,相同參數的請求總是發到同一提供者。
當某一台提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其他提供者,不會引起劇烈變動

4.2多協議:

dubbo支持多種協議:

  • dubbo
  • hessian
  • http
  • rmi
  • webservice
  • thrift
  • memcached
  • redis

不同服務不同協議

不同服務在性能上適用不同協議進行傳輸,比如大數據用短連接協議,小數據大並發用長連接協議

<?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="world"  />
    <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
    <!-- 多協議配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="rmi" port="1099" />
    <!-- 使用dubbo協議暴露服務 -->
    <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
    <!-- 使用rmi協議暴露服務 -->
    <dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" /> 
</beans>

多協議暴露服務

需要與 http 客戶端相互操作

<?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="world"  />
    <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
    <!-- 多協議配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="hessian" port="8080" />
    <!-- 使用多個協議暴露服務 -->
    <dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />
</beans>

4.3、多注冊中心

兩個不同注冊中心,使用豎號分隔多個不同注冊中心地址:

<!-- 多注冊中心配置,豎號分隔表示同時連接多個不同注冊中心,同一注冊中心的多個集群地址用逗號分隔 -->
<dubbo:registry address="10.20.141.150:9090|10.20.154.177:9010" />
<!-- 引用服務 -->
<dubbo:reference id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" />

不同服務使用不同注冊中心:

<!-- 多注冊中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<!-- 向中文站注冊中心注冊 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" />
<!-- 向國際站注冊中心注冊 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />

還可以這樣:

<!-- 多注冊中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<!-- 引用中文站服務 -->
<dubbo:reference id="chinaHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="chinaRegistry" />
<!-- 引用國際站站服務 -->
<dubbo:reference id="intlHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="intlRegistry" />

4.4、超時、重試

超時默認重試 值: 1000ms

重試默認重試2次,不算第一個調用,一共會調用三次

如服務方設置:

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService2" loadbalance="roundrobin" timeout="500" retries="1"/>

注意,本人測試了一下,雖然服務方設置重試次數為1,消費者默認,最終結果還是會重試2次(消費者默認值),所以服務方提供的重試次數無效,建議在消費者設置,但是超時時間是生效的。

超時、重試建議在消費者設置:

<dubbo:reference id="demoService01" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService"
        retries="1" timeout="3000"/>

4.5、分組

當一個接口有多種實現時,可以用 group 區分。

provider.xml

    <dubbo:service id="groupADubboService" group="groupA" interface="org.apache.dubbo.samples.group.api.GroupService"
                   ref="groupAService"/>

    <dubbo:service id="groupBDubboService" group="groupB" interface="org.apache.dubbo.samples.group.api.GroupService"
                   ref="groupBService"/>

consumer.xml

<!-- * 表示 任意組-->
<dubbo:reference group="*" id="groupAService" check="false"
                     interface="org.apache.dubbo.samples.group.api.GroupService" />
<!-- 調用groupB接口 -->
    <!--<dubbo:reference group="groupB" id="groupBService" check="false"-->
                     <!--interface="org.apache.dubbo.samples.group.api.GroupService"/>-->

group="*"group="groupA,groupB" 是一樣的效果,但總是只調一個可用組的實現。(不能實現負載均衡)

這里有個坑,reference group="*" ,consumer在啟動的時候已經選好了分組,並不是輪詢兩個分組

如果你要使用group進行負載均衡,consumer就不要寫group

4.6、版本

當一個接口實現,出現不兼容升級時,可以用版本號過渡,版本號不同的服務相互間不引用。

<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
<dubbo:service interface="com.foo.BarService" version="1.0.0" />

consumer 設置 version="*" 可以 輪詢 調用provider,而group不能,這是和group的最大區別

4.6、直連模式

直連模式一般應用於測試模式。

消費者:

<dubbo:registry id="na" address="N/A" />
<!--使用直連的方式,不需要注冊中心 這里的check表示開啟token-->
<dubbo:reference id="demoService01" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService"
url="dubbo://172.16.44.48:20897"
protocol="dubbo" registry="na"
timeout="3000"
retries="3"
/>

服務方不需要修改,如果開啟了token驗證,需要在<dubbo:provider> 或者 <dubbo:service>聲明:

<dubbo:registry id="default" address="zookeeper://${zookeeper.address:127.0.0.1}:2181" />    
<!--使用dubbo協議,聲明服務的端口-->
<dubbo:protocol id="dubbo1" name="dubbo" port="20897" />
<dubbo:protocol id="dubbo2" name="dubbo" port="20898"/>
<dubbo:provider token="123456" registry="default">
    <!--用 Spring 配置聲明暴露服務 ref 的 值要等 beanId 的 值-->
    <dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService02" loadbalance="roundrobin"
                   timeout="5000" retries="1" protocol="dubbo1"/>
</dubbo:provider>

消費者需要攜帶token:

RpcContext.getContext().setAttachment("token","123456");

如果不需要token驗證,設置成 false 即可

5、不同協議的區別

duboo3.0 的默認協議是 dubbo,較2.0版本來說是一個新的協議(官方稱為triple)

dubbo rmi hessian http webservice thrift
傳輸協議 TCP TCP HTTP HTTP HTTP thrif
傳輸方式 NIO異步傳輸 同步 同步 同步 同步 同步、異步
序列化 Hessian二進制序列化 Java標准二進制序列化 Hessian二進制序列化 表單序列化 SOAP文本序列化 Thrift
適用范圍 傳入傳出參數數據包較小(建議小於100K),消費者比提供者個數多,單一消費者無法壓滿提供者,盡量不要使用dubbo協議傳輸大文件或超大字符串 傳入傳出參數數據包大小混合,消費者與提供者個數差不多,可傳文件。 傳入傳出參數數據包較大,提供者比消費者個數多,提供者壓力較大,可傳文件。 傳入傳出參數數據包大小混合,提供者比消費者個數多,可用瀏覽器查看,可用表單或URL傳入參數,暫不支持傳文件。 系統集成,跨語言調用。 跨語言
約束 參數及返回值需實現Serializable接口 參數及返回值需實現Serializable接口 參數及返回值需實現Serializable接口 不能在協議中傳遞null值

dubbo 有多種協議,不同的協議默認使用不同的序列化框架。比如:

dubbo 協議 默認使用 Hessian2 序列化。(說明:Hessian2 是阿里在 Hessian 基礎上進行的二次開發,起名為Hessian2 )
rmi協議 默認為 java 原生序列化,

http 協議 默認為 為 json 。

hessian 協議,默認是 hessian 序列化;

webservice 協議,默認是 soap 文本序列化 。

6、注意事項(TODO )

1、使用了dubbo2.7.13 版本,thrift 協議 的name 是native-thrift,而且 RpcContext.getContext().getAttachments 無法獲取參數

當前 dubbo 支持的 thrift 協議是對 thrift 原生協議 的擴展,與原生Thrift不兼容 ,使用的是 protocol="tri"

吐槽一下,dubbo3官方的更新進度也太慢了,本人在使用dubbo 3.0.2.1 的時候,並沒有 triple 協議,官方文檔也沒有找到demo,最后是在dubbo-benchmark項目才知道如何使用。

2、協議的支持

dubbo2.7使用默認的序列化協議是hessian,如果參數是泛型 ,返回值可能為null,此時可以修改序列化為 kryo,並加入:

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
</dependency>
<dependency>
    <groupId>de.javakaffee</groupId>
    <artifactId>kryo-serializers</artifactId>
</dependency>

3、版本的區別

目前dubbo 2.7 版本(包括2.7以下)建議使用dubbo作為RPC調用協議(也是默認)。

本人測試了一下,dubbo 3.0 版本情況下即使按照官方文檔,引入 hessian 協議的依賴,仍然報:

No such extension org.apache.dubbo.rpc.Protocol by name hessian, no related exception was found, please check whether related SPI module is missing.

暫時沒有找到解決方案。

使用dubbo 2.7.13 版本,是可以單獨使用hessian協議的。

除此之外本人從網上+測試驗證:

  • dubbo3.0版本是2021年6月才出來的,新版本默認是使用 trilple 協議,還不兼容舊版本協議
  • dubbo3.0官方並沒有詳細的使用文檔,本人測試了一下,與2.7的兼容性還有很大問題,所以建議還是使用2.7版本
  • dubbo更新太慢(3年都沒有更新3.0版本,捐贈給Apache后基本無維護),網上找到的資料不如springcloud多

4、springboot配置文件

建議springboot接入dubbo不要使用 注解的方式 配置dubbo,統一使用xml文件更友好。

5、關於 dubbo-registry-zookeeper 和 dubbo-dependencies-zookeeper

測試了一下,兩個使用其中一個即可,推薦使用 dubbo-registry-zookeeper


參考:


免責聲明!

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



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