天天看點

Dubbo進階應用-服務治理

目錄

1、dubbo-admin-2.7.x版本安裝部署

1.1 下載下傳源碼

1.2 部署通路

2、路由規則

2.1 Dubbo API配置

2.2 管理控制台配置

3、規則動态配置

3.1 應用粒度

3.2 服務粒度

4、服務降級

5、叢集容錯

5.1 叢集容錯模式

5.2 叢集模式配置

6、黑白名單

6.1 應用粒度

6.2 服務粒度

7、權重調整

7.1 應用粒度

7.2 服務粒度

8、負載均衡

8.1 官方提供

8.2 自定義政策

9、優雅停機

9.1 優雅停機原理

9.2 設定方式

10、線上運維Qos

11、簡化注冊中心URL

11.1 為什麼要簡化

11.2 簡化配置

1、dubbo-admin-2.7.x版本安裝部署

1.1 下載下傳源碼

dubbo-admin-2.5.x版本是現階段官方推薦應用到生産的,但是缺陷太多,特别是對于服務治理這一塊,2.7.x版本完善了很多,但是官方并沒有推薦生産使用,不過我覺得能不能用于生産,根據自己的情況來,夠用就行(bug很多,但是留有對應的後門API)

先下載下傳dubbo-admin-2.7.x源碼:https://github.com/apache/dubbo-admin

官網位址:http://dubbo.apache.org/zh-cn/docs/2.7/user/quick-start/

Dubbo進階應用-服務治理

2.7版本作者基于springboot開發的,而且做了前後端分離!

1.2 部署通路

修改zookeeper位址配置,找到\dubbo-admin-develop\dubbo-admin-server\src\main\resources\application.properties:

admin.registry.address=zookeeper://192.168.223.128:2181
admin.config-center=zookeeper://192.168.223.128:2181
admin.metadata-report.address=zookeeper://192.168.223.128:2181
​
admin.root.user.name=root
admin.root.user.password=root
           

在主目錄dubbo-admin-develop目錄下,執行mvn clean package -Dmaven.test.skip=true,第一次會比較慢,因為前端使用了vue.js和node.js,是以你本地沒有安裝npm的會自定下載下傳安裝,慢慢等:

Dubbo進階應用-服務治理

因為使用了springboot,是以不再依賴tomcat容器,有兩種方式啟動

一種方法啟動 :

mvn --projects dubbo-admin-server spring-boot:run 
           

二種方法啟動:

cd dubbo-admin-distribution/target
java -jar dubbo-admin-0.1.jar
           
Dubbo進階應用-服務治理

通路測試:http://localhost:8080

Dubbo進階應用-服務治理

2、路由規則

2.1 Dubbo API配置

需求背景:

  我們現在有一個服務A, 需要暴露在同一個zookeeper上面, 但是注冊到zookeeper的位址需要有公網和内網兩種, 但是我又不想在代碼中做修改.

需求說明:

  同一個服務需要提供内網和公網位址的原因是: 我們有服務B所在的機器隻能通過外網去通路服務A, 但是外網通路會受到帶寬的限制. 但是服務A的請求量又很大, 是以, 我就希望除了服務B以外的機器都通過内網去通路服務A, 這樣就解決了帶寬上面的限制.

  但是, 服務A的叢集是在同一個zookeeper下面的. 是以, 我就必須指定服務B去通路服務A的外網位址的dubbo服務.

  這裡有一個方案: 就是我使用兩個不同的zookeeper, 外網位址的服務A注冊到zookeeper-1上面, 内網位址的注冊到zookeeper-2上面. 這樣也是可以解決上面指定服務B通路服務A的問題.

  但是, 我們上了監控, 監控是監控一個zookeeper位址的服務, 是以, 我就不能有多個zookeeper, 這樣會加大複雜度. 這個時候, 路由規則是一個好東西

路由規則在發起一次RPC調用前起到過濾目标伺服器位址的作用,過濾後的位址清單,将作為消費端最終發起RPC調用的備選位址。

  • 條件路由。支援以服務或Consumer應用為粒度配置路由規則。
  • 标簽路由。以Provider應用為粒度配置路由規則。
@Test
public void test() throws UnknownHostException {
    RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
    Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://192.168.223.128:2181"));
    registry.register(URL.valueOf("condition://0.0.0.0/com.ydt.dubbo.service.LoadBalanceService?category=routers&dynamic=false&rule="
            + URL.encode("host = 192.168.223.* => host = 192.168.224.*")));
}
           

其中:

  • route://

    表示路由規則的類型,支援條件路由規則和腳本路由規則,可擴充,必填。
  • 0.0.0.0

    表示對所有 IP 位址生效,如果隻想對某個 IP 的生效,請填入具體 IP,必填。
  • com.ydt.dubbo.service.LoadBalanceService

    表示隻對指定服務生效,必填。
  • group=loadbalance

    對指定服務的指定group生效,不填表示對未配置group的指定服務生效
  • version=1.0

    對指定服務的指定version生效,不填表示對未配置version的指定服務生效
  • category=routers

    表示該資料為動态配置類型,必填。
  • dynamic=false

    表示該資料為持久資料,當注冊方退出時,資料依然儲存在注冊中心,必填。
  • enabled=true

    覆寫規則是否生效,可不填,預設生效。
  • force=false

    當路由結果為空時,是否強制執行,如果不強制執行,路由結果為空的路由規則将自動失效,可不填,預設為

    false

  • runtime=false

    是否在每次調用時執行路由規則,否則隻在提供者位址清單變更時預先執行并緩存結果,調用時直接從緩存中擷取路由結果。如果用了參數路由,必須設為

    true

    ,需要注意設定會影響調用的性能,可不填,預設為

    false

  • priority=1

    路由規則的優先級,用于排序,優先級越大越靠前執行,可不填,預設為 。
  • rule=URL.encode("host = 192.168.223.* => host = 192.168.224.*")

    表示路由規則的内容,必填。

條件路由規則

基于條件表達式的路由規則,如:

host = 192.168.223.* => host = 192.168.224.*

規則:

  • =>

    之前的為消費者比對條件,所有參數和消費者的 URL 進行對比,當消費者滿足比對條件時,對該消費者執行後面的過濾規則。
  • =>

    之後為提供者位址清單的過濾條件,所有參數和提供者的 URL 進行對比,消費者最終隻拿到過濾後的位址清單。
  • 如果比對條件為空,表示對所有消費方應用,如:

    => host = 192.168.224.*

  • 如果過濾條件為空,表示禁止通路,如:

    host = 192.168.223.* =>

2.2 管理控制台配置

使用API進行配置非常不好了解,而且也做不到動态的修改,是以實際生産中大多時候還是通過管理控制台進行動态配置,特别是對于運維人員來說

2.2.1 條件路由

在Dubbo2.6及更早版本中,所有的服務治理規則都隻針對服務粒度,如果要把某條規則作用到應用粒度上,需要為應用下的所有服務配合相同的規則,變更,删除的時候也需要對應的操作,這樣的操作很不友好,是以Dubbo2.7版本中增加了應用粒度的服務治理操作,對于條件路由(包括黑白名單),動态配置(包括權重,負載均衡)都可以做應用級别的配置

1)、應用粒度

# 消費者dubbo-order隻能消費所有端口為20881的服務執行個體
enabled: true
force: true
runtime: true
conditions:
  - 'application=dubbo-order => address=*:20881'
​
           
Dubbo進階應用-服務治理

怎麼測試也隻會調用dubbo服務端口為20883的服務執行個體:

Dubbo進階應用-服務治理

2)、服務粒度

#com.ydt.dubbo.service.LoadBalanceService的sayHello方法隻能消費所有端口為20880的服務執行個體
enabled: true
force: true
runtime: true
key: com.ydt.dubbo.service.LoadBalanceService
conditions:
  - 'method=sayHello => address=*:20880'
​
           
Dubbo進階應用-服務治理

2.2.2 标簽路由

标簽路由是Dubbo2.7引入的新功能,配置以應用作為次元,給不同的伺服器打上不同名字的标簽,标簽路由通過将某一個或多個服務的提供者劃分到同一個分組,限制流量隻在指定分組中流轉,進而實作流量隔離的目的,可以作為藍綠釋出、灰階釋出等場景的能力基礎。

enabled: true
force: true
runtime: true
tags:
    #在消費者處設定一個全局tag="tag1"
  - name: tag1 
    addresses:
    #如果是本機,請使用四星或者四個0辨別IP來測試,我覺得是dubbo的bug
      - '*.*.*.*:20881'
​
           
<!--消費者全局配置-->
<dubbo:consumer timeout="6000" retries="3" check="false" tag="tag1"/>
           
Dubbo進階應用-服務治理

無論你怎麼通路都是如下結果,隻會消費到dubbo服務端口為20881的執行個體:

Dubbo進階應用-服務治理

3、規則動态配置

動态覆寫規則是Dubbo設計的在無需重新開機應用的情況下,動态調整RPC調用行為的一種能力。2.7.0版本開始,支援從服務和應用兩個粒度來調整動态配置。

3.1 應用粒度

# 将應用dubbo-pay(key:dubbo-pay)在20881端口上提供(side:provider)的所有服務(scope:application)的權重修改為1000(weight:1000,預設都是100)。
configVersion: v2.7
enabled: true
key: dubbo-pay
configs:
  - side: provider
    addresses:
      - '0.0.0.0:20881'
    parameters:
      weight: 1000
           
Dubbo進階應用-服務治理

測試,你會明顯的發現20881所在服務執行個體調用的次數要多得多(因為我這裡一個工程多個端口啟動,是以權重預設都是一樣的)!

3.2 服務粒度

# 所有消費(side:consumer)LoadBalanceService服務(key:com.ydt.dubbo.service.LoadBalanceService)的應用執行個體(addresses:[0.0.0.0]),逾時時間修改為6000ms。
configVersion: v2.7
enabled: true
key: com.ydt.dubbo.service.LoadBalanceService
configs:
  - side: consumer
    addresses:
      - 0.0.0.0
    parameters:
      timeout: 6000
           
Dubbo進階應用-服務治理

4、服務降級

可以通過服務降級功能臨時屏蔽某個出錯的非關鍵服務,并定義降級後的傳回政策,向注冊中心寫入動态配置覆寫規則!

@Test
public void test2(){
    RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
    Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://192.168.223.128:2181"));
    registry.register(URL.valueOf("override://0.0.0.0/com.ydt.dubbo.service.LoadBalanceService?category=configurators&dynamic=false&application=dubbo-order&mock=force:return+error"));
}
           
Dubbo進階應用-服務治理

暫時dubbo-admin不支援服務mock的處理:

Dubbo進階應用-服務治理

5、叢集容錯

在叢集調用失敗時,Dubbo 提供了多種容錯方案,預設為 failover 重試。

5.1 叢集容錯模式

Failover Cluster

失敗自動切換,當出現失敗,重試其它伺服器。通常用于讀操作,但重試會帶來更長延遲。可通過

retries="2"

來設定重試次數(不含第一次,預設也是2次)。

重試次數配置如下:

<dubbo:service retries="2" />
           

<dubbo:reference retries="2" />
           

<dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
           

Failfast Cluster

快速失敗,隻發起一次調用,失敗立即報錯。通常用于非幂等性的寫操作,比如新增記錄。

Failsafe Cluster

失敗安全,出現異常時,直接忽略。通常用于寫入審計日志等操作。

Failback Cluster

失敗自動恢複,背景記錄失敗請求,定時重發。通常用于消息通知操作。

Forking Cluster

并行調用多個伺服器,隻要一個成功即傳回。通常用于實時性要求較高的讀操作,但需要浪費更多服務資源。可通過

forks="2"

來設定最大并行數。

Broadcast Cluster

廣播調用所有提供者,逐個調用,任意一台報錯則報錯。通常用于通知所有提供者更新緩存或日志等本地資源資訊。

5.2 叢集模式配置

按照以下示例在服務提供方和消費方配置叢集模式

<dubbo:service cluster="failsafe" />
           

<dubbo:reference cluster="failsafe" />
           

6、黑白名單

在Dubbo Admin服務治菜單下有黑白名單

,其功能是在應用級别,服務級别針對

IP`設定通路限制

注意:

1、建立黑白名單的時候,可以設定應用級别,也可以設定服務級别,但是不能同時設定

2、吐槽一下,黑白名單貌似沒什麼卵用,隻要你配置了消費者應用或者服務端接口,你就用不了了,我還配個*線,這也是為什麼官方暫時提醒不适用于生産的原因吧!

6.1 應用粒度

Dubbo進階應用-服務治理

打開zookeeper管理控制台可以看到:

Dubbo進階應用-服務治理

現在測試dubbo-order消費者接口通路:

Dubbo進階應用-服務治理

6.2 服務粒度

Dubbo進階應用-服務治理
Dubbo進階應用-服務治理

轉存失敗重新上傳取消

打開zookeeper管理控制台:

Dubbo進階應用-服務治理

測試:

Dubbo進階應用-服務治理

7、權重調整

實作應用和服務級别的負載均衡權重動态配置,因為隻能配置IP級别,本地開發環境配置過于麻煩就不示範了!

7.1 應用粒度

Dubbo進階應用-服務治理

7.2 服務粒度

Dubbo進階應用-服務治理

8、負載均衡

8.1 官方提供

在叢集負載均衡時,Dubbo 提供了多種均衡政策,預設為 Random随機調用。

負載均衡政策

Random LoadBalance(random)

  • 随機,按權重設定随機機率。
  • 在一個截面上碰撞的機率高,但調用量越大分布越均勻,而且按機率使用權重後也比較均勻,有利于動态調整提供者權重。

RoundRobin LoadBalance(roundrobin)

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

LeastActive LoadBalance(leastactive)

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

ConsistentHash LoadBalance(consistenthash)

  • 一緻性 Hash,相同參數的請求總是發到同一提供者。
  • 當某一台提供者挂時,原本發往該提供者的請求,基于虛拟節點,平攤到其它提供者,不會引起劇烈變動。
  • 預設隻對第一個參數 Hash,如果要修改,請配置

    <dubbo:parameter key="hash.arguments" value="0,1" />

  • 預設用 160 份虛拟節點,如果要修改,請配置

    <dubbo:parameter key="hash.nodes" value="320" />

ShortestResponse LoadBalance(shortestresponse)

  • 最短響應時間政策,篩選成功調用響應時間最短的調用程式,并計算這些調用程式的權重和數量
  • 如果隻有一個調用器,則直接使用該調用器
  • 如果有多個調用器,則按随機政策來玩

測試方法:

1、服務提供者開啟三台,設定不同的tomcat和dubbo服務端口

Dubbo進階應用-服務治理

2、服務消費者配置不同的全局負載均衡政策分别進行測試:

<!--消費者全局配置-->
<dubbo:consumer timeout="6000" retries="3" check="false" loadbalance="roundrobin"/>
           
Dubbo進階應用-服務治理

8.2 自定義政策

1、建立一個負載均衡政策類,實作LoadBalance接口

package com.ydt.dubbo.loadbalance;
​
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.RpcException;
​
import java.util.List;
​
public class MyLoadBalance implements LoadBalance {
​
    @Override
    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) 
            throws RpcException {
        //這裡根據你的業務需要實作,我這裡僅僅隻是為了測試,就取了第一個執行機器
        return invokers.get(0);
    }
}
           

2、在resources/META-INF/dubbo/internal下建立純文字檔案,檔案名:org.apache.dubbo.rpc.cluster.LoadBalance,配置負載均衡類索引映射

Dubbo進階應用-服務治理

3、配置自定義負載均衡器的key值:

<!--消費者全局配置-->
<dubbo:consumer timeout="6000" retries="3" check="false" loadbalance="mybalance"/>
           

再次測試,永遠都隻會路由到一個伺服器上了!

9、優雅停機

Dubbo 是通過 JDK 的 ShutdownHook 來完成優雅停機的,是以如果使用者使用

kill -9 PID

等強制關閉指令,是不會執行優雅停機的,隻有通過

kill PID

時,才會執行。

9.1 優雅停機原理

服務提供方

  • 停止時,先标記為不接收新請求,新請求過來時直接報錯,讓用戶端重試其它機器。
  • 然後,檢測線程池中的線程是否正在運作,如果有,等待所有線程執行完成,除非逾時,則強制關閉。

服務消費方

  • 停止時,不再發起新的調用請求,所有新的調用在用戶端即報錯。
  • 然後,檢測有沒有請求的響應還沒有傳回,等待響應傳回,除非逾時,則強制關閉。

9.2 設定方式

設定優雅停機逾時時間,預設逾時時間是 10 秒,如果逾時則強制關閉。

<!--應用名,用于計算依賴關系,不是比對條件,不要與其他應用名一樣 -->
    <dubbo:application name="dubbo-pay">
        <dubbo:parameter key="shutdown.timeout" value="60000" /> <!-- 機關毫秒 -->
    </dubbo:application>
           

如果 ShutdownHook 不能生效,可以自行調用DubboShutdownHook關閉,使用tomcat等容器部署的場景,建議通過擴充ApplicationListener等自行調用以下代碼實作優雅停機:

DubboShutdownHook.destroyAll();
           

現狀測試(因為本地開發要模拟kill -pid不友善,使用如下方式,實際開發中直接加入以下第一步監聽器執行個體即可):

1、建立一個監聽器,實作Spring ApplicationListener

package com.ydt.dubbo.listener;
​
import org.apache.dubbo.config.DubboShutdownHook;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
​
public class ShutdownHookListener implements ApplicationListener {
​
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextClosedEvent) {
            System.out.println("優雅下線啦!");
            DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook();
            shutdownHook.destroyAll();
        }
    }
}
           

2、編寫一個測試類,

@Test
public void test() throws IOException, InterruptedException {
    ClassPathXmlApplicationContext context
            = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
    context.start();
    System.out.println("容器加載完成....");
    final DemoService demoService = (DemoService)context.getBean("demoService"); // 擷取遠端服務代理
    final long start = System.currentTimeMillis();
    new Thread(
            new Runnable() {
                public void run() {
                    System.out.println("别停,哥已經在調用了呢!");
                    System.out.println(demoService.sayHello("laohu"));
                    System.out.println("調用傳回總時間為:" + (System.currentTimeMillis()-start));
                }
            }
    ).start();
    Thread.sleep(1000);//這個地方主要是讓demoService調用線程run起來,如果沒擷取到cpu資源,是不會優雅的
    System.out.println("截止到調用容器銷毀時間為:" + (System.currentTimeMillis()-start));
    context.close();
}
           

3、測試效果

Dubbo進階應用-服務治理

10、線上運維Qos

QoS的英文全稱為"Quality of Service",中文名為"服務品質"。在dubbo 2.5.8 新版本增加了 QOS 子產品,提供了新的 telnet 指令支援。dubbo管它叫線上運維指令,我們可以通過它能夠看到服務提供者狀态,服務調用者狀态,現在dubbo提供了 ls , online,offline,help ,quit指令。

Dubbo進階應用-服務治理

我們可以在dubbo的配置檔案配置參數:

<!--應用名,用于計算依賴關系,不是比對條件,不要與其他應用名一樣 -->
<dubbo:application name="dubbo-pay">
    <!--開啟QOS(線上運維指令,可以對服務進行動态的配置、控制及查詢)-->
    <dubbo:parameter key="qos.enable" value="true"/>
    <dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
    <dubbo:parameter key="qos.port" value="8108"/>
</dubbo:application>
<!--
qos.enable :表示是否開始Qos
qos.accept.foreign.ip: 允許通路的ip,預設就是false,表示不接受任何ip
qos.port: Qos提供服務的端口
-->
           

通過終端通路qos:telnet 127.0.0.1 8108 注意了,如果不是使用本地終端,一些指令是禁止使用的,這也是dubbo的一種保護模式

Dubbo進階應用-服務治理

可以看到服務提供服務與調用服務的狀态 這個 Provider Service Name 就是服務提供者名字 , PUB 就是狀态 N是未注冊,就是沒有注冊到注冊中心,其實服務下線功能就是從注冊中心unregister ,Y表示服務線上,就是注冊到注冊中心了。

其實這個和dubbo-monitor非常相似:

Dubbo進階應用-服務治理

其實都可以在dubbo-monitor上找到原型,其實也就是不想單獨部署dubbo-monitor時使用簡單的操作:

Dubbo進階應用-服務治理

11、簡化注冊中心URL

11.1 為什麼要簡化

dubbo provider中的服務配置項有接近30個配置項。 排除注冊中心服務治理需要之外,很大一部配置設定置項是provider自己使用,不需要透傳給消費者。這部分資料不需要進入注冊中心,而隻需要以key-value形式持久化存儲。

dubbo consumer中的配置項也有20+個配置項。在注冊中心之中,服務消費者清單中隻需要關注application,version,group,ip,dubbo版本等少量配置,其他配置也可以以key-value形式持久化存儲。

這些資料是以服務為次元注冊進入注冊中心,導緻了資料量的膨脹,進而引發注冊中心(如zookeeper)的網絡開銷增大,性能降低。

簡化注冊中心的配置,隻在2.7之後的版本中進行支援。 開啟provider或者consumer簡化配置之後,預設保留的配置項如下:

provider:

Constant Key Key remark
APPLICATION_KEY application
CODEC_KEY codec
EXCHANGER_KEY exchanger
SERIALIZATION_KEY serialization
CLUSTER_KEY cluster
CONNECTIONS_KEY connections
DEPRECATED_KEY deprecated
GROUP_KEY group
LOADBALANCE_KEY loadbalance
MOCK_KEY mock
PATH_KEY path
TIMEOUT_KEY timeout
TOKEN_KEY token
VERSION_KEY version
WARMUP_KEY warmup
WEIGHT_KEY weight
TIMESTAMP_KEY timestamp
DUBBO_VERSION_KEY dubbo
SPECIFICATION_VERSION_KEY specVersion 新增,用于表述dubbo版本,如2.7.0

consumer:

Constant Key Key remark
APPLICATION_KEY application
VERSION_KEY version
GROUP_KEY group
DUBBO_VERSION_KEY dubbo
SPECIFICATION_VERSION_KEY specVersion 新增,用于表述dubbo版本,如2.7.0

11.2 簡化配置

resources目錄下建立dubbo.properties,dubbo架構會預設加載:

Dubbo進階應用-服務治理

配置如下:

#是否開啟簡化
dubbo.registry.simplified=true 
#是否有簡化後的拓展
dubbo.registry.extra-keys=retries,owner
           

spring核心配置加載一個服務接口釋出到注冊中心:

<bean id="loadBalanceService" class="com.ydt.dubbo.service.LoadBalanceServiceImpl"/>
<dubbo:service async="true" inter
               version="1.2.3" group="dubbo-simple" ref="loadBalanceService" executes="4500" retries="7" owner="vict"
               timeout="5300"/>
           

啟動後上zookeeper管理控制台檢視,會發現executes并沒有注冊到注冊中心:

Dubbo進階應用-服務治理

原因:

配置了dubbo.registry.simplified=true, 預設情況下,timeout在預設的配置項清單,是以還是會進入注冊中心;

配置了:dubbo.registry.extra-keys=retries,owner , 是以retries,owner也會進入注冊中心。

總結:timeout,retries,owner進入了注冊中心,而executes沒有進入