Dubbo - 配置示例使用詳解
檢視Dubbo完整配置示例,參考官方文件。
【1】啟動時檢查
Dubbo 預設會在啟動時檢查依賴的服務是否可用,不可用時會丟擲異常,阻止 Spring 初始化完成,以便上線時,能及早發現問題,預設 check=“true”。
可以通過 check=“false” 關閉檢查,比如,測試時,有些服務不關心,或者出現了迴圈依賴,必須有一方先啟動。
另外,如果你的 Spring 容器是懶載入的,或者通過 API 程式設計延遲引用服務,請關閉 check,否則服務臨時不可用時,會丟擲異常,拿到 null 引用,如果 check=“false”,總是會返回引用,當服務恢復時,能自動連上。
① 通過 spring 配置檔案
關閉某個服務的啟動時檢查 (沒有提供者時報錯):
<dubbo:reference interface="com.foo.BarService" check="false" />
關閉所有服務的啟動時檢查 (沒有提供者時報錯):
<dubbo:consumer check="false" />
關閉註冊中心啟動時檢查 (註冊訂閱失敗時報錯):
<dubbo:registry check="false" />
② 通過 dubbo.properties
dubbo.reference.com.foo.BarService.check=false dubbo.reference.check=false dubbo.consumer.check=false dubbo.registry.check=false
③ 通過 -D 引數
java -Ddubbo.reference.com.foo.BarService.check=false
java -Ddubbo.reference.check=false
java -Ddubbo.consumer.check=false
java -Ddubbo.registry.check=false
④ 配置的含義
dubbo.reference.check=false
,強制改變所有 reference 的 check 值,就算配置中有宣告,也會被覆蓋。如<dubbo:reference interface="com.foo.BarService" check="true" />
dubbo.consumer.check=false
,是設定 check 的預設值,如果配置中有顯式的宣告,如:<dubbo:reference interface="com.foo.BarService" check="true" />
,則不會受影響。那些沒有顯示設定check的reference 將會受到影響。
dubbo.registry.check=false
,前面兩個都是指訂閱成功,但提供者列表是否為空是否報錯,如果註冊訂閱失敗時,也允許啟動,需使用此選項,將在後臺定時重試。
⑤ Dubbo的配置
Dubbo的配置有xml配置、屬性配置、API配置和註解配置。XML配置和註解配置就是常規專案中用到的兩種方式,一種是完全使用xml,如傳統專案;一種似乎使用註解代替,如SpringBoot。詳情參考官方文件。
這裡說一下屬性配置,如上面看到的①②③。
如果公共配置很簡單,沒有多註冊中心,多協議等情況,或者想多個 Spring 容器想共享配置,可以使用 dubbo.properties 作為預設配置。
Dubbo 將自動載入 classpath 根目錄下的 dubbo.properties,可以通過JVM啟動引數-Ddubbo.properties.file=xxx.properties
改變預設配置位置。
覆蓋策略
JVM 啟動 -D 引數優先,這樣可以使使用者在部署和啟動時進行引數重寫,比如在啟動時需改變協議的埠。
XML 次之,如果在 XML 中有配置,則 dubbo.properties 中的相應配置項無效。
Properties 最後,相當於預設值,只有 XML 沒有配置時,dubbo.properties 的相應配置項才會生效,通常用於共享公共配置,比如應用名。
【2】服務呼叫超時設定和重試次數
① 超時timeout屬性設定
當呼叫一個服務長時間得不到響應的時候,並不會讓其一直阻塞等待下去。大量執行緒阻塞等待響應會引起效能下降,這時就需要設定超時屬性-timeout。
dubbo:reference的timeout屬性預設使用<dubbo:consumer>
的timeout屬性,而後者的timeout屬性預設值為1000。參考schema配置參考手冊。
服務消費者配置例項如下:
<dubbo:reference interface="com.web.gmall.service.UserService"
id="userService" timeout="5000" >
<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
</dubbo:reference>
<!-- 配置當前消費者的統一規則:所有的服務都不檢查 -->
<dubbo:consumer check="false" timeout="5000"></dubbo:consumer>
服務提供者配置例項如下:
<!-- 暴露服務 ref:指向服務的真正的實現物件 -->
<dubbo:service interface="com.web.gmall.service.UserService"
ref="userServiceImpl" timeout="1000" >
<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
</dubbo:service>
<!--統一設定服務提供方的規則 -->
<dubbo:provider timeout="1000"></dubbo:provider>
這時候就有有個問題,哪個配置的timeout屬性生效?
在官方文件xml配置中,說明了該問題。
② xml配置覆蓋關係
以 timeout 為例,顯示了配置的查詢順序,其它 retries, loadbalance, actives 等類似:
- 方法級優先,介面級次之,全域性配置再次之。
- 如果級別一樣,則消費方優先,提供方次之。
其中,服務提供方配置,通過 URL 經由註冊中心傳遞給消費方。
建議由服務提供方設定超時,因為一個方法需要執行多長時間,服務提供方更清楚,如果一個消費方同時引用多個服務,就不需要關心每個服務的超時設定。
理論上 ReferenceConfig 的非服務標識配置,在 ConsumerConfig,ServiceConfig, ProviderConfig 均可以預設配置。
③ 重試次數retries屬性
為了提高可用性和冗錯率,可以設定retries屬性。dubbo:reference的retries屬性預設使用<dubbo:consumer>
的retries屬性。而<dubbo:consumer>
的retries屬性預設值為2。
消費者例項設定如下:
<dubbo:reference interface="com.web.gmall.service.UserService"
id="userService" timeout="5000" retries="3" >
<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
</dubbo:reference>
//設定retries="3"表示除第一次呼叫外再嘗試呼叫三次,總共呼叫四次。
如果服務提供者如UserService有多個例項,消費者重試的時候還會嘗試呼叫其他UserService例項。
那麼是否所有情況下都應該設定重試次數?答案當然是否定的!
如果每次的操作結果都一樣,那麼應該可以進行重試,這種情況稱之為冪等。如果每次操作結果都不一樣,那麼不應該能夠重試,這種情況稱之為非冪等。冪等操作如查詢、刪除和修改,非冪等操作如新增。
舉個例子,如消費者呼叫提供者進行資料庫新增,在提供者插入資料庫過程中,消費者超時了,這時就不應該再次重試。
禁止重試,只需要將retries設定為0即可。如下所示:
<dubbo:reference interface="com.web.gmall.service.UserService"
id="userService" timeout="5000" retries="3" version="*">
<dubbo:method name="insertUser" timeout="1000" retries="0"></dubbo:method>
介面級別可以重試三次,insertUser該方法禁止重試。
故而在系統設計的時候重試次數一定要額外注意,該值預設值為2。
【3】多版本
當一個介面實現,出現不相容升級時,可以用版本號過渡,版本號不同的服務相互間不引用。
可以按照以下的步驟進行版本遷移:
0.在低壓力時間段,先升級一半提供者為新版本
1.再將所有消費者升級為新版本
2.然後將剩下的一半提供者升級為新版本
老版本服務提供者配置:
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
新版本服務提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" />
老版本服務消費者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
新版本服務消費者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />
如果不需要區分版本,可以按照以下的方式配置 :
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
這樣就可以從舊版本平滑過渡到新版本,也就是Dubbo官網介紹的灰度釋出。
【4】本地存根Stub
遠端服務後,客戶端通常只剩下介面,而實現全在伺服器端,但提供方有些時候想在客戶端也執行部分邏輯,比如:做 ThreadLocal 快取,提前驗證引數,呼叫失敗後偽造容錯資料等等,此時就需要在 API 中帶上 Stub,客戶端生成 Proxy 例項,會把 Proxy 通過建構函式傳給 Stub,然後把 Stub 暴露給使用者,Stub 可以決定要不要去調 Proxy。
dubbo:service的stub屬性
值型別為class/boolean,預設值為false。設為true,表示使用預設代理類名,即:介面名 + Local字尾,服務介面客戶端本地代理類名,用於在客戶端執行本地邏輯,如本地快取等,該本地代理類的建構函式必須允許傳入遠端代理物件,建構函式如:public XxxServiceLocal(XxxService xxxService)
例項
如下所示,這裡將介面抽取到了gmall-interface專案中,order-service-consumer和user-service-provider均依賴該專案。故而在gmall-interface專案中,新增UserServiceStub即可。
UserServiceStub例項如下:
public class UserServiceStub implements UserService {
private final UserService userService;
/**
* 傳入的是userService遠端的代理物件
* @param userService
*/
public UserServiceStub(UserService userService) {
super();
this.userService = userService;
}
@Override
public List<UserAddress> getUserAddressList(String userId) {
// TODO Auto-generated method stub
System.out.println("UserServiceStub.....");
if(userId!=null&&userId!="") {
return userService.getUserAddressList(userId);
}
return null;
}
}
在user-service-provider專案中配置如下:
<dubbo:service interface="com.web.gmall.service.UserService"
ref="userServiceImpl" timeout="1000"
stub="com.web.gmall.service.stub.UserServiceStub" >
<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
</dubbo:service>
分別啟動provider和consumer,測試如下:
使用者id:1
UserServiceStub.....
北京市昌平區巨集福科技園綜合樓3層
深圳市寶安區西部矽谷大廈B座3層(深圳分校)
呼叫完成...
可以看到在發起遠端呼叫之前,首先呼叫了UserServiceStub 。