dubbo配置之屬性配置原則、啟動檢查、超時時間、重試次數、多版本
之前我們簡單介紹了dubbo配置服務提供者、消費者以及管理平臺監控平臺,接下來我們再說一下dubbo的其他配置。
1.配置策略
1.1 屬性配置
dubbo可以在JVM 啟動引數、dubboXML、dubbo.properties 三個地方配置相關屬性,這裡我們以埠為例.
- JVM 啟動引數
我們可以在啟動專案時配置VM引數
-Ddubbo.protocol.port=20883
- dubboXML
<dubbo:protocol name="dubbo" port="20882"></dubbo:protocol >
- dubbo.properties
dubbo.protocol.port=20881
覆蓋策略
JVM 啟動 -D 引數優先,這樣可以使使用者在部署和啟動時進行引數重寫,比如在啟動時需改變協議的埠。
XML 次之,如果在 XML 中有配置,則 dubbo.properties 中的相應配置項無效。
Properties 最後,相當於預設值,只有 XML 沒有配置時,dubbo.properties 的相應配置項才會生效,通常用於共享公共配置,比如應用名。
1.2 XML配置
前面介紹了服務提供者介面的配置
<dubbo:service interface="com.yz.dubbo.api.IUserService" ref="userService1" timeout="1000"></dubbo:service>
當然我們只是把timeout
屬性配置在了介面上,而介面中有那麼多方法,所以我們還可以具體配置到方法
<dubbo:service interface="com.yz.dubbo.api.IUserService" ref="userService1" >
<dubbo:method name="getUser" timeout="2000"></dubbo:method>
</dubbo:service>
這樣我們就指定了getUser
方法timeout
屬性
但是服務提供者和消費者有那麼多的介面一個一個配置豈不是太麻煩,所以我們可以將一樣的配置抽取出來作為服務提供者以及消費者的預設配置
<dubbo:provider timeout="3000"></dubbo:provider>
以 timeout 為例,顯示了配置的查詢順序,其它 retries, loadbalance, actives 等類似
- 方法級優先,介面級次之,全域性配置再次之。
- 如果級別一樣,則消費方優先,提供方次之。
其中,服務提供方配置,通過 URL 經由註冊中心傳遞給消費方。
建議由服務提供方設定超時,因為一個方法需要執行多長時間,服務提供方更清楚,如果一個消費方同時引用多個服務,就不需要關心每個服務的超時設定。
2.啟動檢查
Dubbo 預設會在啟動時檢查依賴的服務是否可用,不可用時會丟擲異常,阻止 Spring 初始化完成,以便上線時,能及早發現問題,預設 check=“true”。
可以通過 check=“false” 關閉檢查,比如,測試時,有些服務不關心,或者出現了迴圈依賴,必須有一方先啟動。
例子
當我們沒有配置檢查屬性的時候.只啟動消費者,可以看到控制檯輸出錯誤資訊 No provider
我們配置啟動檢查check
為false
<dubbo:reference id="userService" interface="com.yz.dubbo.api.IUserService" check="false"></dubbo:reference>
當我們設定check="false"
時,在沒有提供者的情況下,消費者啟動是不會報錯的
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "classpath:customer.xml" });
final IUserService demoService = (IUserService) context.getBean("userService");
// System.out.println(demoService.getUser());
System.out.println("程式執行......");
System.in.read();
,只有在顯示呼叫提供者服務的時候才會報錯
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "classpath:customer.xml" });
final IUserService demoService = (IUserService) context.getBean("userService");
System.out.println(demoService.getUser());
System.out.println("程式執行......");
System.in.read();
可以看到程式報錯,就是顯示呼叫 demoService.getUser()
這段程式碼導致的
註冊中心檢查
dubbo.registry.check=false
我們可以通過以上配置關閉服務提供者消費者對註冊中心的檢查,這樣註冊中心掛掉了,我們服務提供者消費者啟動也不會報錯,只是不能註冊服務而已…
例子
當我們的註冊中心掛掉的時候,我們啟動服務消費者以及提供者是會報錯的
我們只需要配置註冊中心不檢查,啟動就不會報錯而且當註冊中心重新恢復的時候他們會自動的訂閱服務以及註冊服務
<dubbo:registry address="zookeeper://127.0.0.1:2181" check="false"></dubbo:registry>
3.超時時間
由於網路或服務端不可靠,會導致調用出現一種不確定的中間狀態(超時)。為了避免超時導致客戶端資源(執行緒)掛起耗盡,必須設定超時時間。
在現實的開發中我們往往一些服務提供者的呼叫比較耗時,而dubbo的timeout
預設配置為1000
毫秒,也就是說當消費者呼叫服務提供者一秒鐘還沒有返回結果,則消費者會報錯,如下
提供者
public class UserServiceImpl implements IUserService{
@Override
public List<User> getUser() throws UserException {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Arrays.asList(new User[]{new User(1,"yz","china","hlj")
,new User(2,"zwl","china","ah")
,new User(3,"hhj","china","zj")});
}
}
我們模擬耗時,讓提供者睡眠三秒鐘,接下來啟動提供者消費者
可以看到消費者在等待一秒後還沒有結果就報錯,所以在線上我們可以通過設定timeout來避擴音供者服務耗時帶來的問題
<dubbo:service interface="com.yz.dubbo.api.IUserService" ref="userService1" timeout="4000"></dubbo:service>
消費者在等待三秒後,提供者服務已經被正常呼叫
4.重試次數
當我們服務消費者消費出現失敗,可通過 retries="2"
來設定重試次數(不含第一次),多次呼叫服務提供者
例子
首先我們去掉之前的timeout
屬性來模擬出錯,並加上retries
來實現重試
<dubbo:reference id="userService" interface="com.yz.dubbo.api.IUserService" check="false" retries="3"></dubbo:reference>
提供者
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("被呼叫了............");
return Arrays.asList(new User[]{new User(1,"yz","china","hlj")
,new User(2,"zwl","china","ah")
,new User(3,"hhj","china","zj")});
接下來我們分別啟動服務提供者與消費者,可以看到,我們消費者在呼叫失敗後提供者被呼叫了四次
5.多版本
當一個介面實現,出現不相容升級時,可以用版本號過渡,版本號不同的服務相互間不引用。
可以按照以下的步驟進行版本遷移:
- 在低壓力時間段,先升級一半提供者為新版本
- 再將所有消費者升級為新版本
- 然後將剩下的一半提供者升級為新版本
也就實現了dubbo所說的灰度釋出
例子
首先我們建立提供者介面兩個不同實現
UserServiceImpl
@Override
public List<User> getUser() throws UserException {
System.out.println("被呼叫了1............");
return Arrays.asList(new User[]{new User(1,"yz","china","hlj")
,new User(2,"zwl","china","ah")
,new User(3,"hhj","china","zj")});
}
UserServiceImpl2
@Override
public List<User> getUser() throws UserException {
System.out.println("被呼叫了2............");
return Arrays.asList(new User[]{new User(1,"yz","china","hlj")
,new User(2,"zwl","china","ah")
,new User(3,"hhj","china","zj")});
}
接下來在provider.xml
配置檔案中提供者介面實現指向不同的兩個類,並指定不同的版本
<bean id="userService1" class="com.yz.dubbo.impl.UserServiceImpl"></bean>
<bean id="userService2" class="com.yz.dubbo.impl.UserServiceImpl2"></bean>
<dubbo:service interface="com.yz.dubbo.api.IUserService" ref="userService1" version="1.0.0"></dubbo:service>
<dubbo:service interface="com.yz.dubbo.api.IUserService" ref="userService2" version="2.0.0"></dubbo:service>
在customer.xml
中指定消費者的版本號為1.0.0
<dubbo:reference id="userService" interface="com.yz.dubbo.api.IUserService" check="false" version="1.0.0"></dubbo:reference>
在customer.xml
中指定消費者的版本號為2.0.0
<dubbo:reference id="userService" interface="com.yz.dubbo.api.IUserService" check="false" version="2.0.0"></dubbo:reference>
可以看到了通過指定版本號分別呼叫了不同的介面實現,這樣在實際開發中就能夠實現新舊功能的過度