原文連結: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.cluster
、dubbo.consumer.cluster
和 dubbo.service.cluster
、dubbo.provider.cluster
等屬性配置。
叢集容錯中主要有幾個角色:
Invoker:Provider 的一個可呼叫 Service 的抽象,Invoker 封裝了 Provider 地址以及 Service 介面資訊。
Directory:代表多個 Invoker ,可以把它看成是 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
(兩端) 屬性直接將併發執行控制到介面的某個方法。