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" />
2,集羣容錯在集羣調用失敗時,Dubbo 提供了多種容錯方案,缺省爲 failover 重試。
各節點關係:
- 這裏的
Invoker
是Provider
的一個可調用Service
的抽象,Invoker
封裝了Provider
地址及Service
接口信息 Directory
代表多個Invoker
,可以把它看成List<Invoker>
,但與List
不同的是,它的值可能是動態變化的,比如註冊中心推送變更Cluster
將Directory
中的多個Invoker
僞裝成一個Invoker
,對上層透明,僞裝過程包含了容錯邏輯,調用失敗後,重試另一個Router
負責從多個Invoker
中按路由規則選出子集,比如讀寫分離,應用隔離等LoadBalance
負責從多個Invoker
中選出具體的一個用於本次調用,選的過程包含了負載均衡算法,調用失敗後,需要重選
Failover Cluster
失敗自動切換,當出現失敗,重試其它服務器 1。通常用於讀操作,但重試會帶來更長延遲。可通過 retries="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
廣播調用所有提供者,逐個調用,任意一臺報錯則報錯 2。通常用於通知所有提供者更新緩存或日誌等本地資源信息。
集羣模式配置
按照以下示例在服務提供方和消費方配置集羣模式
<dubbo:service cluster="failsafe" />
或
<dubbo:reference cluster="failsafe" />
3,負載均衡在集羣負載均衡時,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:service interface="..." loadbalance="roundrobin" />
客戶端服務級別
<dubbo:reference interface="..." loadbalance="roundrobin" />
服務端方法級別
<dubbo:service interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
客戶端方法級別
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
如果事件處理的邏輯能迅速完成,並且不會發起新的 IO 請求,比如只是在內存中記個標識,則直接在 IO 線程上處理更快,因爲減少了線程池調度。
但如果事件處理邏輯較慢,或者需要發起新的 IO 請求,比如需要查詢數據庫,則必須派發到線程池,否則 IO 線程阻塞,將導致不能接收其它請求。
如果用 IO 線程處理事件,又在事件處理過程中發起新的 IO 請求,比如在連接事件中發起登錄請求,會報“可能引發死鎖”異常,但不會真死鎖。
因此,需要通過不同的派發策略和不同的線程池配置的組合來應對不同的場景:
<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
Dispatcher
all
所有消息都派發到線程池,包括請求,響應,連接事件,斷開事件,心跳等。direct
所有消息都不派發到線程池,全部在 IO 線程上直接執行。message
只有請求響應消息派發到線程池,其它連接斷開事件,心跳等消息,直接在 IO 線程上執行。execution
只請求消息派發到線程池,不含響應,響應和其它連接斷開事件,心跳等消息,直接在 IO 線程上執行。connection
在 IO 線程上,將連接斷開事件放入隊列,有序逐個執行,其它消息派發到線程池。
ThreadPool
fixed
固定大小線程池,啓動時建立線程,不關閉,一直持有。(缺省)cached
緩存線程池,空閒一分鐘自動刪除,需要時重建。limited
可伸縮線程池,但池中的線程數只會增長不會收縮。只增長不收縮的目的是爲了避免收縮時突然來了大流量引起的性能問題。eager
優先創建Worker
線程池。在任務數量大於corePoolSize
但是小於maximumPoolSize
時,優先創建Worker
來處理任務。當任務數量大於maximumPoolSize
時,將任務放入阻塞隊列中。阻塞隊列充滿時拋出RejectedExecutionException
。(相比於cached
:cached
在任務數量超過maximumPoolSize
時直接拋出異常而不是將任務放入阻塞隊列)
爲方便開發測試,經常會在線下共用一個所有服務可用的註冊中心,這時,如果一個正在開發中的服務提供者註冊,可能會影響消費者不能正常運行。
可以讓服務提供者開發方,只訂閱服務(開發的服務可能依賴其它服務),而不註冊正在開發的服務,通過直連測試正在開發的服務。
禁用註冊配置
<dubbo:registry address="10.20.153.10:9090" register="false" />
或者
<dubbo:registry address="10.20.153.10:9090?register=false" />
如果有兩個鏡像環境,兩個註冊中心,有一個服務只在其中一個註冊中心有部署,另一個註冊中心還沒來得及部署,而兩個註冊中心的其它應用都需要依賴此服務。這個時候,可以讓服務提供者方只註冊服務到另一註冊中心,而不從另一註冊中心訂閱服務。
禁用訂閱配置
<dubbo:registry id="hzRegistry" address="10.20.153.10:9090" />
<dubbo:registry id="qdRegistry" address="10.20.141.150:9090" subscribe="false" />
或者
<dubbo:registry id="hzRegistry" address="10.20.153.10:9090" />
<dubbo:registry id="qdRegistry" address="10.20.141.150:9090?subscribe=false" />
Dubbo 允許配置多協議,在不同服務上支持不同協議或者同一服務上同時支持多種協議。
不同服務不同協議
不同服務在性能上適用不同協議進行傳輸,比如大數據用短連接協議,小數據大併發用長連接協議
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="world" />
<dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
<!-- 多協議配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />
<!-- 使用dubbo協議暴露服務 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
<!-- 使用rmi協議暴露服務 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" />
</beans>
多協議暴露服務
需要與 http 客戶端互操作
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="world" />
<dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
<!-- 多協議配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="hessian" port="8080" />
<!-- 使用多個協議暴露服務 -->
<dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />
</beans>
8,多註冊中心Dubbo 支持同一服務向多註冊中心同時註冊,或者不同服務分別註冊到不同的註冊中心上去,甚至可以同時引用註冊在不同註冊中心上的同名服務。另外,註冊中心是支持自定義擴展的 1。
多註冊中心註冊
比如:中文站有些服務來不及在青島部署,只在杭州部署,而青島的其它應用需要引用此服務,就可以將服務同時註冊到兩個註冊中心。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="world" />
<!-- 多註冊中心配置 -->
<dubbo:registry id="hangzhouRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="qingdaoRegistry" address="10.20.141.151:9010" default="false" />
<!-- 向多個註冊中心註冊 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="hangzhouRegistry,qingdaoRegistry" />
</beans>
不同服務使用不同註冊中心
比如:CRM 有些服務是專門爲國際站設計的,有些服務是專門爲中文站設計的。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="world" />
<!-- 多註冊中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<!-- 向中文站註冊中心註冊 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" />
<!-- 向國際站註冊中心註冊 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />
</beans>
多註冊中心引用
比如:CRM 需同時調用中文站和國際站的 PC2 服務,PC2 在中文站和國際站均有部署,接口及版本號都一樣,但連的數據庫不一樣。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="world" />
<!-- 多註冊中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<!-- 引用中文站服務 -->
<dubbo:reference id="chinaHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="chinaRegistry" />
<!-- 引用國際站站服務 -->
<dubbo:reference id="intlHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="intlRegistry" />
</beans>
如果只是測試環境臨時需要連接兩個不同註冊中心,使用豎號分隔多個不同註冊中心地址:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="world" />
<!-- 多註冊中心配置,豎號分隔表示同時連接多個不同註冊中心,同一註冊中心的多個集羣地址用逗號分隔 -->
<dubbo:registry address="10.20.141.150:9090|10.20.154.177:9010" />
<!-- 引用服務 -->
<dubbo:reference id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" />
</beans>
9,服務分組當一個接口有多種實現時,可以用 group 區分。
服務
<dubbo:service group="feedback" interface="com.xxx.IndexService" />
<dubbo:service group="member" interface="com.xxx.IndexService" />
引用
<dubbo:reference id="feedbackIndexService" group="feedback" interface="com.xxx.IndexService" />
<dubbo:reference id="memberIndexService" group="member" interface="com.xxx.IndexService" />
任意組 1:
<dubbo:reference id="barService" interface="com.foo.BarService" group="*" />
10,分組聚合按組合並返回結果 1,比如菜單服務,接口一樣,但有多種實現,用group區分,現在消費方需從每種group中調用一次返回結果,合併結果返回,這樣就可以實現聚合菜單項。
相關代碼可以參考 dubbo 項目中的示例
配置
搜索所有分組
<dubbo:reference interface="com.xxx.MenuService" group="*" merger="true" />
合併指定分組
<dubbo:reference interface="com.xxx.MenuService" group="aaa,bbb" merger="true" />
指定方法合併結果,其它未指定的方法,將只調用一個 Group
<dubbo:reference interface="com.xxx.MenuService" group="*">
<dubbo:method name="getMenuItems" merger="true" />
</dubbo:service>
某個方法不合並結果,其它都合併結果
<dubbo:reference interface="com.xxx.MenuService" group="*" merger="true">
<dubbo:method name="getMenuItems" merger="false" />
</dubbo:service>
指定合併策略,缺省根據返回值類型自動匹配,如果同一類型有兩個合併器時,需指定合併器的名稱 2
<dubbo:reference interface="com.xxx.MenuService" group="*">
<dubbo:method name="getMenuItems" merger="mymerge" />
</dubbo:service>
指定合併方法,將調用返回結果的指定方法進行合併,合併方法的參數類型必須是返回結果類型本身
<dubbo:reference interface="com.xxx.MenuService" group="*">
<dubbo:method name="getMenuItems" merger=".addAll" />
</dubbo:service>