Dubbo官網實戰使用技巧

不送花的程式猿發表於2021-02-03

原文連結:Dubbo官網實戰使用技巧

1、啟動時檢查:

我們檢查依賴的服務是否啟動,可利用下面三個屬性,優先順序從左到右逐漸降低。
如果服務不是強依賴,或者說服務之間可能存在死迴圈依賴,我們應該將 check 置為 false。

檢查判斷優先順序:
dubbo.reference.check > dubbo.consumer.check > dubbo.registry.check

2、只訂閱:

一般在開發環境時,我們新開發的介面都還不能釋出出去,所以我們本地的服務不能往註冊中心註冊;
而且,如果我們將本地服務註冊上去,會影響別的服務的聯調,所以我們會利用下面屬性,將服務設定為只訂閱,不往註冊中心註冊。

dubbo.registry.register=false
dubbo.registry.subscribe=true

3、叢集容錯:

叢集容錯模式可利用 dubbo.reference.clusterdubbo.consumer.clusterdubbo.service.clusterdubbo.provider.cluster 等屬性配置。

叢集容錯中主要有幾個角色:

Invoker:Provider 的一個可呼叫 Service 的抽象,Invoker 封裝了 Provider 地址以及 Service 介面資訊。

Directory:代表多個 Invoker ,可以把它看成是 List,但是與 List 不同的是,它的值可能是動態變化的,比如註冊中心推送變更。

Cluster:將 Directory 中的多個 Invoker 偽裝成一個 Invoker,對上層透明,偽裝過程包含了容錯邏輯,呼叫失敗後,重試另一個。

Router:負責從多個 Invoker 中按路由規則選出子集,比如讀寫分離,應用隔離等。

LoadBalance:負責從多個 Invoker 中選出具體的一個用於本次呼叫,選的過程包含了負載均衡演算法,呼叫失敗後,需要重選

dubbo 提供的叢集容錯模式:

Failover Cluster:失敗自動切換,當出現失敗,重試其它伺服器。通常用於讀操作,但重試會帶來更長延遲。可通過 retries="2" 來設定重試次數(不含第一次)。

Failfast Cluster:快速失敗,即只發起一次呼叫,失敗立即報錯。通常用於非冪等性的寫操作。

Failsafe Cluster:失敗安全,出現異常時直接忽略掉。通常用於寫入審計日誌等不重要的操作。

Failback Cluster:失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於訊息通知操作。

Forking Cluster:並行呼叫多個伺服器,只要一個成功就返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks="2" 來設定最大並行數。

Broadcast Cluster:廣播呼叫所有提供者,逐個呼叫,任意一臺報錯則報錯。通常用於通知所有提供者更新快取或日誌等本地資源資訊。

4、負載均衡:

在叢集負載均衡時,Dubbo 提供了多種均衡策略,預設為 random 隨機呼叫。

Random LoadBalance:

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

RoundRobin LoadBalance:

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

LeastActive LoadBalance:

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

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.provider.loadbalance=leastactive
dubbo.consumer.loadbalance=leastactive

服務端方法級別和客戶端方法級別配置:

@DubboService(interfaceClass = DubboServiceOne.class,loadbalance = "random",
                methods = {
                    @Method(name="sayHello",loadbalance = "leastActive")
                })
public class DubboServiceOneImpl implements DubboServiceOne {}

@DubboReference(loadbalance = "random",
                    methods = {
                        @Method(name="sayHello",loadbalance = "leastactive")
                    })
private DubboServiceOne DubboServiceOne;

5、直連提供者

在開發及測試環境下,經常需要繞過註冊中心,只測試指定服務提供者,這時候可能需要點對點直連,點對點直連方式,將以服務介面為單位,忽略註冊中心的提供者列表,A 介面配置點對點,不影響 B 介面從註冊中心獲取列表。

在 JVM 啟動引數中加入 -D 引數對映服務地址:

java -D com.alibaba.xxx.XxxService=dubbo://localhost:20890

<dubbo.reference>標籤或者@DubboResource註解中增加 url 屬性。

<debbo.reference url="dubbo://localhost:20890" interfaceClass=""/>
@DubboReference(url="dubbo://localhost:20890")
private DubboServiceOne DubboServiceOne;

6、本地呼叫

本地呼叫使用了 injvm 協議,是一個偽協議,它不開啟埠,不發起遠端呼叫,只在 JVM 內直接關聯,但執行 Dubbo 的 Filter 鏈。

protocol、provider、consumer、service、reference 都可以設定。

7、本地存根

遠端服務後,客戶端通常只剩下介面,而實現全在伺服器端,但提供方有些時候想在客戶端也執行部分邏輯,比如:做 ThreadLocal 快取,提前驗證引數,呼叫失敗後偽造容錯資料等等,此時就需要在 API 中帶上 Stub,客戶端生成 Proxy 例項,會把 Proxy 通過建構函式傳給 Stub ,然後把 Stub 暴露給使用者,Stub 可以決定要不要去調 Proxy。

Sub 利用 dubbo.service.sub 屬性設定。

例子:

假設服務提供者提供了一個介面,DubboServiceOne,然後服務消費者要做本地存根,只需要在自己的專案中,增加一個 DubboServiceOne 介面的實現類,然後在 @DubboReference 註解或者 <dubbo:reference> 標籤增加 stub 屬性即可。

實現類:

/**
 * DubboServiceOne 本地存根
 * @author winfun
 * @date 2021/2/1 9:59 上午
 **/
@Slf4j
public class DubboServiceOneStub implements DubboServiceOne {

    private final DubboServiceOne dubboServiceOne;

    public DubboServiceOneStub(DubboServiceOne dubboServiceOne){
        this.dubboServiceOne = dubboServiceOne;
    }

    /***
     *  say hello
     * @author winfun
     * @param name name
     * @return {@link ApiResult <String> }
     **/
    @Override
    public ApiResult<String> sayHello(String name) {
        try {
            ApiResult<String> result = this.dubboServiceOne.sayHello(name);
            if (ApiContants.SUCCESS.equals(result.getCode())){
                return ApiResult.fail(ApiContants.FAIL,"業務異常",result.getData());
            }
        }catch (Exception e){
            log.error("call DubboServiceOne throw exception!message is {}",e.getMessage());
            return ApiResult.fail("呼叫失敗");
        }
        return null;
    }
}

使用:

/**
 * 測試本地存根
 * @author winfun
 * @date 2021/2/1 10:26 上午
 **/
@RestController
public class TestStubController {

    @DubboReference(lazy = true,check = false,stub = "com.winfun.demo.stub.DubboServiceOneStub")
    private DubboServiceOne dubboServiceOne;

    @GetMapping("/stub/{name}")
    public ApiResult<String> testStub(@PathVariable("name") String name){
        return this.dubboServiceOne.sayHello(name);
    }
}

8、本地偽裝

本地偽裝通常用於服務降級,比如某驗權服務,當服務提供方全部掛掉後,客戶端不丟擲異常,而是通過 mock 資料返回授權失敗。

mock 是 sub 的一個子集,mock是發生了錯誤,也就是丟擲 RpcException 異常時會觸發;而使用 sub,那麼就需要在程式捕獲異常,然後進行處理。

mock 機制可利用<dubbo.reference>標籤或者@DubboReference的mock屬性設定。

詳細可看我自己寫的文章:https://blog.csdn.net/Howinfun/article/details/113439208

9、服務延遲暴露

Dubbo 2.6.5 之後,所有服務都將在 Spring 初始化完成後進行暴露,如果你不需要延遲暴露服務,無需配置 delay。

可使用 dubbo.service.delay 屬性來設定延遲多少秒暴露服務。delay 的時間單位為毫秒。

10、併發控制

併發控制都是在服務提供者端設定的。

首先,可通過 dubbo.service.executes 屬性限制服務端每個方法的併發量(佔用執行緒池執行緒數)、通過 dubbo.method.executes(服務端) 屬性直接將併發限制具體到介面的某個方法。

還可以通過 dubbo.service.actives/dubbo.reference.actives 屬性控制介面每個方法每個客戶端的併發執行數;
通過 dubbo.method.actives(兩端) 屬性直接將併發執行控制到介面的某個方法。

相關文章