2、屬性配置說明
2.1或舞、【cluster】屬性配置說明
cluster屬性定義服務(wù)調(diào)用者在調(diào)用服務(wù)失敗后的處理策略荆姆。
failover(默認(rèn)):
- 失敗自動切換,當(dāng)出現(xiàn)失敗映凳,重試其他服務(wù)器胆筒。
- 通常用于讀操作,但重試會帶來更長延遲诈豌。
- 可通過retries=x來設(shè)置重試次數(shù)(不含第一次)仆救。
failfast:
- 快速失敗,只發(fā)起一次調(diào)用矫渔,失敗理解報(bào)錯彤蔽。
- 通常用于非冪等性的寫操作,比如新增記錄庙洼。
failsafe:
- 失敗安全顿痪,出現(xiàn)異常時(shí),直接忽略油够;
- 通常用于寫入審計(jì)日志等操作蚁袭。
failback:
- 失敗自動回復(fù),后臺記錄失敗請求石咬,定時(shí)重發(fā)揩悄。
- 通常用于消息通知操作。
forking:
- 并行調(diào)用多個服務(wù)器鬼悠,只要一個成功即返回虏束。
- 通常用于實(shí)時(shí)性要求較高的讀操作,但需要浪費(fèi)更多服務(wù)資源厦章。
- 可通過forks=x來設(shè)置最大并行數(shù)。
broadcast:
- 廣播調(diào)用所有提供者照藻,逐個調(diào)用袜啃,任意一臺報(bào)錯則報(bào)錯。
- 通常用于通知所有提供者更新緩存或日志等本地資源信息幸缕。
2.2群发、【loadbalance】屬性配置說明
loadbalance屬性定義服務(wù)調(diào)用者在調(diào)用服務(wù)時(shí)選取服務(wù)提供者的負(fù)載均衡策略晰韵。
random:
- 隨機(jī),按權(quán)重設(shè)置隨機(jī)概率熟妓。
- 在一個截面上碰撞的概率高雪猪,但調(diào)用量越大分布越均勻,而且按概率使用權(quán)重后也比較均勻起愈,有利于動態(tài)調(diào)整提供者權(quán)重只恨。
roundrobin:
- 輪詢,按公約后的權(quán)重設(shè)置輪詢比率抬虽。
- 存在慢的提供者累計(jì)請求問題官觅,比如:第二臺機(jī)器很慢,但沒掛阐污,當(dāng)請求調(diào)用到第二臺是就卡在那休涤,久而久之,所有請求都卡在掉第二臺上笛辟。
leastactive:
- 最少活躍調(diào)用數(shù)功氨,相同活躍數(shù)的隨機(jī),活躍數(shù)指調(diào)用前后計(jì)數(shù)差手幢。
- 使慢的提供者收到更少請求捷凄,因?yàn)樵铰奶峁┱叩恼{(diào)用前后計(jì)數(shù)差會越大。
consistenthash:
- 一致性Hash纵势,相同參數(shù)的請求總是發(fā)到同一提供者。
- 當(dāng)某一臺提供者掛掉時(shí)鸳玩,原本發(fā)往該提供者的請求,基于虛擬節(jié)點(diǎn)瘪板,平攤到其他提供者惊橱,不會引起劇烈變動。
- 算法參見:https://en.wikipedia.org/wiki/Consistent_hashiing
- 缺省只對第一個參考Hash涵但,如果要修改,請配置<dubbo:parameter key="hash.arguments" value="0,1" />
- 缺省用160份虛擬節(jié)點(diǎn)拳球,如果要修改,請配置<dubbo:parameter key="hash.nodes" value="320" />
2.3谚赎、【check】屬性配置說明
check屬性為啟動時(shí)檢查迎吵,dubbo缺省會在啟動時(shí)檢查依賴的服務(wù)是否可用圆仔,不可用時(shí)會拋出異常信姓,阻止Spring初始化完成,以便上線時(shí)绸罗,能及早發(fā)現(xiàn)問題意推,默認(rèn)【check=true】。
2.4珊蟀、線程模型配置說明
事件處理線程說明:
- 如果事件處理的邏輯能迅速完成菊值,并且不會發(fā)起新的IO請求外驱,比如只是在內(nèi)存中記錄一個標(biāo)記,則直接在IO線程上處理更快腻窒,因?yàn)闇p少線程調(diào)度昵宇。
- 但如果事件處理邏輯較慢,或者需要發(fā)起新的IO請求儿子,比如需要查詢數(shù)據(jù)庫瓦哎,則必須派發(fā)到線程池,否則IO線程阻塞柔逼,將導(dǎo)致不能接受其他請求蒋譬。
- 如果用IO線程處理事件,又在事件處理過程中發(fā)起新的IO請求愉适,比如在連接事件中發(fā)起登錄請求犯助,會報(bào)“可能引發(fā)死鎖”異常,但不會真死鎖维咸。
dispatcher屬性:
- all:所有消息都派發(fā)到線程池剂买,包括請求,響應(yīng)腰湾,連接事件雷恃,斷開事件,心跳等费坊。
- direct:所有消息都不派發(fā)到線程池倒槐,全部在IO線程上直接執(zhí)行。
- message:只有請求響應(yīng)消息派發(fā)到線程池附井,其他連接斷開事件讨越,心跳等消息,直接在IO線程上執(zhí)行永毅;
- execution:只請求消息派發(fā)到線程池把跨,不含響應(yīng),響應(yīng)和其他連接斷開事件沼死,心跳等消息着逐,直接在IO線程上執(zhí)行。
- connection:在IO線程上意蛀,將連接斷開事件放入隊(duì)列耸别,有序逐個執(zhí)行,其他消息派發(fā)到線程池县钥。
threadpool屬性:
- fixed:固定大小線程池秀姐,啟動時(shí)建立線程,不關(guān)閉若贮,一直有省有。(缺恃髁簟)
- cached:緩存線程池,空閑一分鐘自動刪除蠢沿,需要時(shí)重建伸头。
- limited:可伸縮線程池,但池中的線程數(shù)只會增長不會收縮舷蟀。(為避免收縮是突然來了大流量引起性能問題)熊锭。
threads屬性:
設(shè)置線程池中線程的數(shù)量。
2.5雪侥、點(diǎn)對點(diǎn)直連
在開發(fā)及測試環(huán)境下,經(jīng)常需要繞過注冊中心精绎,只測試指定的服務(wù)提供者速缨,這時(shí)可能需要點(diǎn)對點(diǎn)直連,點(diǎn)對點(diǎn)直連方式代乃,將以服務(wù)接口為單位旬牲,忽略注冊中心的提供者列表,A接口配置點(diǎn)對點(diǎn)搁吓,不影響B(tài)接口從注冊中心獲取列表原茅。
- 如果是線上需要點(diǎn)對點(diǎn),可在<dubbo:reference>中配置url執(zhí)行提供者堕仔,將繞過注冊中心擂橘, 多個地址用分號隔開,配置如下:
<dubbo:reference interface="com.alibab.xxx.XxxService" url="dubbo://localhost:20890" />
- 在JVM啟動參數(shù)中加入-D參數(shù)映射服務(wù)地址摩骨,如:
java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:2890
key為服務(wù)名:com.alibaba.xxx.XxxService通贞;value為服務(wù)提供者url,此配置優(yōu)先級最高恼五。.
- 如果線上服務(wù)比較多昌罩,也可用文件映射,如:
java -Ddubbo.resolve.file=xxx.properties
然后再映射文件xxx.properties中加入:
com.alibaba.xxx.XxxService=dubbo://localhost:2890
用-Ddubbo.resolve.file指定映射文件路徑灾馒,此配置優(yōu)先級高于<dubbo:reference>中的配置茎用,1.0.15+版本支持,2.0+版本自動加載${user.home}/dubbo-resolve.properties文件睬罗,不需要配置轨功。
2.6、只訂閱/只注冊
只訂閱:
為方便開發(fā)測試傅物,經(jīng)常會在線下公用一個所有服務(wù)可用的注冊中心夯辖,這時(shí),如果一個正在開發(fā)中的服務(wù)提供者注冊董饰,可能會影響消費(fèi)者不能正常運(yùn)行蒿褂。
可用讓服務(wù)提供者開發(fā)方圆米,只訂閱服務(wù)(開發(fā)的服務(wù)可能依賴其他服務(wù)),而不注冊正在開發(fā)的服務(wù)啄栓,通過直連測試正在開發(fā)的服務(wù)娄帖。
配置如下:
<dubbo:registry address="192.168.101.100:20800" register=“false” />
或:
<dubbo:registry address="192.168.101.100:20800?register=false” />
只注冊:
如果有兩個鏡像環(huán)境,兩個注冊中心昙楚,有一個服務(wù)只在其中一個注冊中心有部署近速,另一個注冊中心還沒來得及部署,而兩個注冊中心的其他應(yīng)用都需要依賴此服務(wù)堪旧,所以需要將服務(wù)同時(shí)注冊到兩個注冊中心削葱,但卻不能讓此服務(wù)同時(shí)依賴兩個注冊中心的其他服務(wù)摆马。
可以讓服務(wù)提供者方办铡,只注冊服務(wù)到另一注冊中心诡延,而不是另一注冊中心訂閱服務(wù)悉患。
禁用訂閱配置:
<dubbo:registry id="test1Registry" address="192.168.101.100:9999" />
<dubbo:registry id="test2Registry" address="192.168.101.111:9999" subscribe="false" />
或者:
<dubbo:registry id="test1Registry" address="192.168.101.100:9999" />
<dubbo:registry id="test2Registry" address="192.168.101.111:9999?subscribe=false" />
<meta charset="utf-8">
2.7进肯、靜態(tài)服務(wù)
有時(shí)候希望人工管理服務(wù)提供者的上線和下線坚嗜,此時(shí)需將注冊中心標(biāo)識為非動態(tài)管理模式践宴。
<dubbo:registry address="192.168.101.100:9999" dynamic="false" />
或者:
<dubbo:registry address="192.168.101.100:9999?dynamic=false" />
服務(wù)提供者初次注冊是為禁用狀態(tài)哨查,需人工啟用陨囊,斷線時(shí)弦疮,將不會被自動刪除,需人工禁用蜘醋。
2.8胁塞、多協(xié)議
(1)不同服務(wù)不同協(xié)議:
如:不同服務(wù)在性能上適用不同協(xié)議進(jìn)行傳輸,比如大數(shù)據(jù)用短連接協(xié)議堂湖,小數(shù)據(jù)大并發(fā)用長連接協(xié)議闲先。
<meta charset="utf-8">
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns=" [http://www.springframework.org/schema/beans"](http://www.springframework.org/schema/beans)
xmlns:xsi=" [http://www.w3.org/2001/XMLSchema-instance"](http://www.w3.org/2001/XMLSchema-instance)
xmlns:dubbo=" [http://code.alibabatech.com/schema/dubbo"](http://code.alibabatech.com/schema/dubbo)
xsi:schemaLocation=" [http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)
[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)
[http://code.alibabatech.com/schema/dubbo](http://code.alibabatech.com/schema/dubbo)
[http://code.alibabatech.com/schema/dubbo/dubbo.xsd](http://code.alibabatech.com/schema/dubbo/dubbo.xsd)
">
<dubbo:applicationname="world" />
<dubbo:registryid="registry"address="10.20.141.150:9090"username="admin"password="hello1234"/>
<!-- 多協(xié)議配置 -->
<dubbo:protocolname="dubbo"port="20880"/>
<dubbo:protocolname="rmi"port="1099"/>
<!-- 使用dubbo協(xié)議暴露服務(wù) -->
<dubbo:serviceinterface="com.alibaba.hello.api.HelloService"version="1.0.0"ref="helloService"protocol="dubbo"/>
<!-- 使用rmi協(xié)議暴露服務(wù) -->
<dubbo:serviceinterface="com.alibaba.hello.api.DemoService"version="1.0.0"ref="demoService"protocol="rmi"/>
</beans>
(2)多協(xié)議暴露服務(wù)
如:需要與http客戶端操作
<meta charset="utf-8">
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns=" [http://www.springframework.org/schema/beans"](http://www.springframework.org/schema/beans)
xmlns:xsi=" [http://www.w3.org/2001/XMLSchema-instance"](http://www.w3.org/2001/XMLSchema-instance)
xmlns:dubbo=" [http://code.alibabatech.com/schema/dubbo"](http://code.alibabatech.com/schema/dubbo)
xsi:schemaLocation=" [http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)
[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)
[http://code.alibabatech.com/schema/dubbo](http://code.alibabatech.com/schema/dubbo)
[http://code.alibabatech.com/schema/dubbo/dubbo.xsd](http://code.alibabatech.com/schema/dubbo/dubbo.xsd)
">
<dubbo:applicationname="world" />
<dubbo:registryid="registry"address="10.20.141.150:9090"username="admin"password="hello1234"/>
<!-- 多協(xié)議配置 -->
<dubbo:protocolname="dubbo"port="20880"/>
<dubbo:protocolname="hessian"port="8080"/>
<!-- 使用多個協(xié)議暴露服務(wù) -->
<dubbo:serviceid="helloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"protocol="dubbo,hessian"/>
</beans>
2.9、多注冊中心
(1) 多注冊中心注冊
比如:中文站有些服務(wù)來不及在青島部署无蜂,只在杭州部署伺糠,而青島的其它應(yīng)用需要引用此服務(wù),就可以將服務(wù)同時(shí)注冊到兩個注冊中心斥季。
<meta charset="utf-8">
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns=" [http://www.springframework.org/schema/beans"](http://www.springframework.org/schema/beans)
xmlns:xsi=" [http://www.w3.org/2001/XMLSchema-instance"](http://www.w3.org/2001/XMLSchema-instance)
xmlns:dubbo=" [http://code.alibabatech.com/schema/dubbo"](http://code.alibabatech.com/schema/dubbo)
xsi:schemaLocation=" [http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)
[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)
[http://code.alibabatech.com/schema/dubbo](http://code.alibabatech.com/schema/dubbo)
[http://code.alibabatech.com/schema/dubbo/dubbo.xsd](http://code.alibabatech.com/schema/dubbo/dubbo.xsd)
">
<dubbo:applicationname="world" />
<!-- 多注冊中心配置 -->
<dubbo:registryid="hangzhouRegistry"address="10.20.141.150:9090"/>
<dubbo:registryid="qingdaoRegistry"address="10.20.141.151:9010"default="false"/>
<!-- 向多個注冊中心注冊 -->
<dubbo:serviceinterface="com.alibaba.hello.api.HelloService"version="1.0.0"ref="helloService"registry="hangzhouRegistry,qingdaoRegistry"/>
</beans>
(2) 不同服務(wù)使用不同注冊中心
比如:CRM有些服務(wù)是專門為國際站設(shè)計(jì)的训桶,有些服務(wù)是專門為中文站設(shè)計(jì)的。
<meta charset="utf-8">
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns=" [http://www.springframework.org/schema/beans"](http://www.springframework.org/schema/beans)
xmlns:xsi=" [http://www.w3.org/2001/XMLSchema-instance"](http://www.w3.org/2001/XMLSchema-instance)
xmlns:dubbo=" [http://code.alibabatech.com/schema/dubbo"](http://code.alibabatech.com/schema/dubbo)
xsi:schemaLocation=" [http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)
[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)
[http://code.alibabatech.com/schema/dubbo](http://code.alibabatech.com/schema/dubbo)
[http://code.alibabatech.com/schema/dubbo/dubbo.xsd](http://code.alibabatech.com/schema/dubbo/dubbo.xsd)
">
<dubbo:applicationname="world" />
<!-- 多注冊中心配置 -->
<dubbo:registryid="chinaRegistry"address="10.20.141.150:9090"/>
<dubbo:registryid="intlRegistry"address="10.20.154.177:9010"default="false"/>
<!-- 向中文站注冊中心注冊 -->
<dubbo:serviceinterface="com.alibaba.hello.api.HelloService"version="1.0.0"ref="helloService"registry="chinaRegistry"/>
<!-- 向國際站注冊中心注冊 -->
<dubbo:serviceinterface="com.alibaba.hello.api.DemoService"version="1.0.0"ref="demoService"registry="intlRegistry"/>
</beans>
(3) 多注冊中心引用
比如:CRM需同時(shí)調(diào)用中文站和國際站的PC2服務(wù)酣倾,PC2在中文站和國際站均有部署舵揭,接口及版本號都一樣,但連的數(shù)據(jù)庫不一樣躁锡。
<meta charset="utf-8">
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns=" [http://www.springframework.org/schema/beans"](http://www.springframework.org/schema/beans)
xmlns:xsi=" [http://www.w3.org/2001/XMLSchema-instance"](http://www.w3.org/2001/XMLSchema-instance)
xmlns:dubbo=" [http://code.alibabatech.com/schema/dubbo"](http://code.alibabatech.com/schema/dubbo)
xsi:schemaLocation=" [http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)
[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)
[http://code.alibabatech.com/schema/dubbo](http://code.alibabatech.com/schema/dubbo)
[http://code.alibabatech.com/schema/dubbo/dubbo.xsd](http://code.alibabatech.com/schema/dubbo/dubbo.xsd)
">
<dubbo:applicationname="world" />
<!-- 多注冊中心配置 -->
<dubbo:registryid="chinaRegistry"address="10.20.141.150:9090"/>
<dubbo:registryid="intlRegistry"address="10.20.154.177:9010"default="false"/>
<!-- 引用中文站服務(wù) -->
<dubbo:referenceid="chinaHelloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"registry="chinaRegistry"/>
<!-- 引用國際站站服務(wù) -->
<dubbo:referenceid="intlHelloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"registry="intlRegistry"/>
</beans>
如果只是測試環(huán)境臨時(shí)需要連接兩個不同注冊中心午绳,使用豎號分隔多個不同注冊中心地址:
<meta charset="utf-8">
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns=" [http://www.springframework.org/schema/beans"](http://www.springframework.org/schema/beans)
xmlns:xsi=" [http://www.w3.org/2001/XMLSchema-instance"](http://www.w3.org/2001/XMLSchema-instance)
xmlns:dubbo=" [http://code.alibabatech.com/schema/dubbo"](http://code.alibabatech.com/schema/dubbo)
xsi:schemaLocation=" [http://www.springframework.org/schema/beans](http://www.springframework.org/schema/beans)
[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)
[http://code.alibabatech.com/schema/dubbo](http://code.alibabatech.com/schema/dubbo)
[http://code.alibabatech.com/schema/dubbo/dubbo.xsd](http://code.alibabatech.com/schema/dubbo/dubbo.xsd)
">
<dubbo:applicationname="world" />
<!-- 多注冊中心配置,豎號分隔表示同時(shí)連接多個不同注冊中心映之,同一注冊中心的多個集群地址用逗號分隔 -->
<dubbo:registryaddress="10.20.141.150:9090|10.20.154.177:9010"/>
<!-- 引用服務(wù) -->
<dubbo:referenceid="helloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"/>
</beans>
2.10拦焚、服務(wù)分組
當(dāng)一個接口有多種實(shí)現(xiàn)時(shí)蜡坊,可以用group區(qū)分。
服務(wù)提供者配置:
<dubbo:service group="china" interface="com.xxx.IndexService"/>
<dubbo:service group="India" interface="com.xxx.IndexService"/>
服務(wù)調(diào)用者配置:
<dubbo:reference id="chinaIndexService" group="china" interface="com.xxx.IndexService"/>
<dubbo:reference id="indiaIndexService" group="India" interface="com.xxx.IndexService"/>
任意組:(2.2.0以上版本支持赎败,總是只調(diào)一個可用組的實(shí)現(xiàn))
<dubbo:reference id="barService" interface="com.foo.BarService" group="*"/>
2.11秕衙、多版本
當(dāng)一個接口實(shí)現(xiàn),出現(xiàn)不兼容升級時(shí)僵刮,可以用版本號過渡据忘,版本號不同的服務(wù)相互間不引用。
- 在低壓力時(shí)間段搞糕,先升級一半提供者為新版本
- 再將所有消費(fèi)者升級為新版本
- 然后將剩下的一半提供者升級為新版本
服務(wù)提供者:
<dubbo:service interface="com.foo.BarService" version="1.0.0"/>
<dubbo:service interface="com.foo.BarService" version="2.0.0"/>
服務(wù)消費(fèi)者:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0"/>
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0"/>
不區(qū)分版本:(2.2.0以上版本支持)
<dubbo:referenceid="barService"interface="com.foo.BarService"version="*"/>
2.12勇吊、分組聚合
按組合并返回結(jié)果,比如菜單服務(wù)窍仰,接口一樣萧福,但有多種實(shí)現(xiàn),用group區(qū)分辈赋,現(xiàn)在消費(fèi)方需從每種group中調(diào)用一次返回結(jié)果,合并結(jié)果返回膏燕,這樣就可以實(shí)現(xiàn)聚合菜單項(xiàng)钥屈。(從2.1.0版本開始支持)
配置如:(搜索所有分組)
<dubbo:reference interface="com.xxx.MenuService" group="*" merger="true"/>
或:(合并指定分組)
<dubbo:referenceinterface="com.xxx.MenuService"group="aaa,bbb"merger="true"/>
或:(指定方法合并結(jié)果,其它未指定的方法坝辫,將只調(diào)用一個Group)
<dubbo:referenceinterface="com.xxx.MenuService"group="*">
<dubbo:methodname="getMenuItems"merger="true"/>
</dubbo:service>
或:(某個方法不合并結(jié)果篷就,其它都合并結(jié)果)
<dubbo:referenceinterface="com.xxx.MenuService"group="*"merger="true">
<dubbo:methodname="getMenuItems"merger="false"/>
</dubbo:service>
或:(指定合并策略,缺省根據(jù)返回值類型自動匹配近忙,如果同一類型有兩個合并器時(shí)竭业,需指定合并器的名稱)參見:[合并結(jié)果擴(kuò)展]
<dubbo:referenceinterface="com.xxx.MenuService"group="*">
<dubbo:methodname="getMenuItems"merger="mymerge"/>
</dubbo:service>
或:(指定合并方法,將調(diào)用返回結(jié)果的指定方法進(jìn)行合并及舍,合并方法的參數(shù)類型必須是返回結(jié)果類型本身)
<dubbo:referenceinterface="com.xxx.MenuService"group="*">
<dubbo:methodname="getMenuItems"merger=".addAll"/>
</dubbo:service>
2.13未辆、結(jié)果緩存
結(jié)果緩存,用于加速熱門數(shù)據(jù)的訪問速度锯玛,Dubbo提供聲明式緩存咐柜,以減少用戶加緩存的工作量。
- lru: 基于最近最少使用原則刪除多余緩存攘残,保持最熱的數(shù)據(jù)被緩存拙友。
- threadlocal: 當(dāng)前線程緩存,比如一個頁面渲染歼郭,用到很多portal遗契,每個portal都要去查用戶信息,通過線程緩存病曾,可以減少這種多余訪問牍蜂。
- jcache: 與JSR107集成漾根,可以橋接各種緩存實(shí)現(xiàn)。
配置如下:
<dubbo:referenceinterface="com.foo.BarService"cache="lru"/>
或:
<dubbo:referenceinterface="com.foo.BarService">
<dubbo:methodname="findBar"cache="lru"/>
</dubbo:reference>
2.14捷兰、上下文信息
上下文中存放的是當(dāng)前調(diào)用過程中所需的環(huán)境信息立叛。所有配置信息都將轉(zhuǎn)換為URL的參數(shù)。
RpcContext是一個ThreadLocal的臨時(shí)狀態(tài)記錄器贡茅,當(dāng)接收到RPC請求秘蛇,或發(fā)起RPC請求時(shí),RpcContext的狀態(tài)都會變化顶考。比如:A調(diào)B赁还,B再調(diào)C,則B機(jī)器上驹沿,在B調(diào)C之前艘策,RpcContext記錄的是A調(diào)B的信息,在B調(diào)C之后渊季,RpcContext記錄的是B調(diào)C的信息朋蔫。
(1) 服務(wù)消費(fèi)方:
xxxService.xxx();// 遠(yuǎn)程調(diào)用
boolean isConsumerSide = RpcContext.getContext().isConsumerSide();// 本端是否為消費(fèi)端,這里會返回true
String serverIP = RpcContext.getContext().getRemoteHost();// 獲取最后一次調(diào)用的提供方IP地址
String application = RpcContext.getContext().getUrl().getParameter("application");// 獲取當(dāng)前服務(wù)配置信息却汉,所有配置信息都將轉(zhuǎn)換為URL的參數(shù)
// ...
yyyService.yyy();// 注意:每發(fā)起RPC調(diào)用驯妄,上下文狀態(tài)會變化
// ...
(2) 服務(wù)提供方
public class XxxService Implimplements XxxService {
public void xxx() {// 服務(wù)方法實(shí)現(xiàn)
boolean isProviderSide = RpcContext.getContext().isProviderSide();// 本端是否為提供端,這里會返回true
String clientIP = RpcContext.getContext().getRemoteHost();// 獲取調(diào)用方IP地址
String application = RpcContext.getContext().getUrl().getParameter("application");// 獲取當(dāng)前服務(wù)配置信息合砂,所有配置信息都將轉(zhuǎn)換為URL的參數(shù)
// ...
yyyService.yyy();// 注意:每發(fā)起RPC調(diào)用青扔,上下文狀態(tài)會變化
booleanisProviderSide = RpcContext.getContext().isProviderSide();// 此時(shí)本端變成消費(fèi)端,這里會返回false
// ...
}
}
2.15翩伪、隱試傳參
注:path,group,version,dubbo,token,timeout幾個key有特殊處理微猖,請使用其它key值。
(1) 服務(wù)消費(fèi)方:
RpcContext.getContext().setAttachment("index","1");// 隱式傳參缘屹,后面的遠(yuǎn)程調(diào)用都會隱式將這些參數(shù)發(fā)送到服務(wù)器端凛剥,類似cookie,用于框架集成轻姿,不建議常規(guī)業(yè)務(wù)使用
xxxService.xxx();// 遠(yuǎn)程調(diào)用
// ...
【注】 setAttachment設(shè)置的KV当悔,在完成下面一次遠(yuǎn)程調(diào)用會被清空。即多次遠(yuǎn)程調(diào)用要多次設(shè)置踢代。
(2) 服務(wù)提供方:
public class XxxService Implimplements XxxService {
publicvoidxxx() {// 服務(wù)方法實(shí)現(xiàn)
String index = RpcContext.getContext().getAttachment("index");// 獲取客戶端隱式傳入的參數(shù)盲憎,用于框架集成,不建議常規(guī)業(yè)務(wù)使用
// ...
}
}
2.16胳挎、異步調(diào)用
基于NIO的非阻塞實(shí)現(xiàn)并行調(diào)用饼疙,客戶端不需要啟動多線程即可完成并行調(diào)用多個遠(yuǎn)程服務(wù),相對多線程開銷較小。(2.0.6及其以上版本支持)
配置聲明:
consumer.xml
<dubbo:reference id="fooService" interface="com.alibaba.foo.FooService">
<dubbo:method name="findFoo" async="true"/>
</dubbo:reference>
<dubbo:reference id="barService" interface="com.alibaba.bar.BarService">
<dubbo:method name="findBar" async="true"/>
</dubbo:reference>
調(diào)用代碼:
fooService.findFoo(fooId);// 此調(diào)用會立即返回null
Future<Foo> fooFuture = RpcContext.getContext().getFuture();// 拿到調(diào)用的Future引用窑眯,當(dāng)結(jié)果返回后屏积,會被通知和設(shè)置到此Future。
barService.findBar(barId);// 此調(diào)用會立即返回null
Future<Bar> barFuture = RpcContext.getContext().getFuture();// 拿到調(diào)用的Future引用磅甩,當(dāng)結(jié)果返回后炊林,會被通知和設(shè)置到此Future。
// 此時(shí)findFoo和findBar的請求同時(shí)在執(zhí)行卷要,客戶端不需要啟動多線程來支持并行渣聚,而是借助NIO的非阻塞完成。
Foo foo = fooFuture.get();// 如果foo已返回僧叉,直接拿到返回值奕枝,否則線程wait住,等待foo返回后瓶堕,線程會被notify喚醒隘道。
Bar bar = barFuture.get();// 同理等待bar返回。
// 如果foo需要5秒返回郎笆,bar需要6秒返回谭梗,實(shí)際只需等6秒,即可獲取到foo和bar宛蚓,進(jìn)行接下來的處理默辨。
你也可以設(shè)置是否等待消息發(fā)出:(異步總是不等待返回)
- sent="true" :等待消息發(fā)出,消息發(fā)送失敗將拋出異常苍息。
- sent="false" :不等待消息發(fā)出,將消息放入IO隊(duì)列壹置,即刻返回竞思。
<dubbo:methodname="findFoo"async="true"sent="true"/>
如果你只是想異步,完全忽略返回值钞护,可以配置return="false"盖喷,以減少Future對象的創(chuàng)建和管理成本:
<dubbo:methodname="findFoo"async="true"return="false"/>
2.17、事件通知
在調(diào)用之前难咕,調(diào)用之后课梳,出現(xiàn)異常時(shí),會觸發(fā)oninvoke, onreturn, onthrow三個事件余佃,可以配置當(dāng)事件發(fā)生時(shí)暮刃,通知哪個類的哪個方法。(支持版本:2.0.7之后)
(1) 服務(wù)提供者與消費(fèi)者共享服務(wù)接口:
IDemoService.java
interfaceIDemoService {
publicPerson get(intid);
}
(2) 服務(wù)提供者實(shí)現(xiàn):
DemoServiceImpl.java
classNormalDemoServiceimplementsIDemoService {
publicPerson get(intid) {
returnnewPerson(id,"charles`son",4);
}
}
(3) 服務(wù)提供者配置:
provider.xml
<dubbo:applicationname="rpc-callback-demo"/>
<dubbo:registryaddress="10.20.153.186"/>
<beanid="demoService"class="com.alibaba.dubbo.callback.implicit.NormalDemoService"/>
<dubbo:serviceinterface="com.alibaba.dubbo.callback.implicit.IDemoService"ref="demoService"version="1.0.0"group="cn"/>
(4) 服務(wù)消費(fèi)者Callback接口及實(shí)現(xiàn):
Nofify.java
interface Nofify {
public void onreturn(Person msg, Integer id);
public void onthrow(Throwable ex, Integer id);
}
NofifyImpl.java
class NofifyImpl implements Nofify {
publicMap<Integer, Person> ret =newHashMap<Integer, Person>();
publicMap<Integer, Throwable> errors =newHashMap<Integer, Throwable>();
public void onreturn(Person msg, Integer id) {
System.out.println("onreturn:"+ msg);
ret.put(id, msg);
}
public void onthrow(Throwable ex, Integer id) {
errors.put(id, ex);
}
}
(5) 服務(wù)消費(fèi)者Callback接口及實(shí)現(xiàn):
consumer.xml
<beanid="demoCallback"class="com.alibaba.dubbo.callback.implicit.NofifyImpl"/>
<dubbo:referenceid="demoService"interface="com.alibaba.dubbo.callback.implicit.IDemoService"version="1.0.0"group="cn">
<dubbo:methodname="get"async="true"onreturn="demoCallback.onreturn"onthrow="demoCallback.onthrow"/>
</dubbo:reference>
注:
callback與async功能正交分解:
async=true爆土,表示結(jié)果是否馬上返回.
onreturn 表示是否需要回調(diào).
- 組合情況:(async=false 默認(rèn))
- 異步回調(diào)模式:async=true onreturn="xxx"
- 同步回調(diào)模式:async=false onreturn="xxx"
- 異步無回調(diào) :async=true
- 同步無回調(diào) :async=false
(6) TEST CASE:
Test.java
IDemoService demoService = (IDemoService) context.getBean("demoService");
NofifyImpl notify = (NofifyImpl) context.getBean("demoCallback");
intrequestId =2;
Person ret = demoService.get(requestId);
Assert.assertEquals(null, ret);
//for Test:只是用來說明callback正常被調(diào)用椭懊,業(yè)務(wù)具體實(shí)現(xiàn)自行決定.
for(inti =0; i <10; i++) {
if(!notify.ret.containsKey(requestId)) {
Thread.sleep(200);
}else{
break;
}
}
Assert.assertEquals(requestId, notify.ret.get(requestId).getId());
2.18、本地存根
遠(yuǎn)程服務(wù)后步势,客戶端通常只剩下接口氧猬,而實(shí)現(xiàn)全在服務(wù)器端背犯,但提供方有些時(shí)候想在客戶端也執(zhí)行部分邏輯,比如:做ThreadLocal緩存盅抚,提前驗(yàn)證參數(shù)漠魏,調(diào)用失敗后偽造容錯數(shù)據(jù)等等,此時(shí)就需要在API中帶上Stub妄均,客戶端生成Proxy實(shí)柱锹,會把Proxy通過構(gòu)造函數(shù)傳給Stub,然后把Stub暴露組給用戶丛晦,Stub可以決定要不要去調(diào)Proxy奕纫。Stub必須有可傳入Proxy的構(gòu)造函數(shù)。
<dubbo:service interface="com.foo.BarService" stub="true"/>
或:
<dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub"/>
api.jar:
com.foo.BarService
com.foo.BarServiceStub // 在API旁邊放一個Stub實(shí)現(xiàn)烫沙,它實(shí)現(xiàn)BarService接口匹层,并有一個傳入遠(yuǎn)程BarService實(shí)例的構(gòu)造函數(shù)
packagecom.foo
publicclassBarServiceStubimplementsBarService {
privatefinalBarService barService;
// 構(gòu)造函數(shù)傳入真正的遠(yuǎn)程代理對象
public(BarService barService) {
this.barService = barService;
}
publicString sayHello(String name) {
// 此代碼在客戶端執(zhí)行
// 你可以在客戶端做ThreadLocal本地緩存,或預(yù)先驗(yàn)證參數(shù)是否合法锌蓄,等等
try{
returnbarService.sayHello(name);
}catch(Exception e) {
// 你可以容錯升筏,可以做任何AOP攔截事項(xiàng)
return"容錯數(shù)據(jù)";
}
}
}
2.19、本地偽裝
Mock通常用于服務(wù)降級瘸爽,比如某驗(yàn)權(quán)服務(wù)您访,當(dāng)服務(wù)提供方全部掛掉后,客戶端不拋出異常剪决,而是通過Mock數(shù)據(jù)返回授權(quán)失敗灵汪。
Mock是Stub的一個子集,便于服務(wù)提供方在客戶端執(zhí)行容錯邏輯柑潦,因經(jīng)常需要在出現(xiàn)RpcException(比如網(wǎng)絡(luò)失敗享言,超時(shí)等)時(shí)進(jìn)行容錯,而在出現(xiàn)業(yè)務(wù)異常(比如登錄用戶名密碼錯誤)時(shí)不需要容錯渗鬼,如果用Stub览露,可能就需要捕獲并依賴RpcException類,而用Mock就可以不依賴RpcException譬胎,因?yàn)樗募s定就是只有出現(xiàn)RpcException時(shí)才執(zhí)行差牛。
<dubbo:service interface="com.foo.BarService" mock="true"/>
或:
<dubbo:service interface="com.foo.BarService" mock="com.foo.BarServiceMock"/>
api.jar:
com.foo.BarService
com.foo.BarServiceMock // 在API旁邊放一個Mock實(shí)現(xiàn),它實(shí)現(xiàn)BarService接口堰乔,并有一個無參構(gòu)造函數(shù)
packagecom.foo
publicclassBarServiceMockimplementsBarService {
publicString sayHello(String name) {
// 你可以偽造容錯數(shù)據(jù)偏化,此方法只在出現(xiàn)RpcException時(shí)被執(zhí)行
return"容錯數(shù)據(jù)";
}
}
如果服務(wù)的消費(fèi)方經(jīng)常需要try-catch捕獲異常,如:
Offer offer =null;
try{
offer = offerService.findOffer(offerId);
}catch(RpcException e) {
logger.error(e);
}
請考慮改為Mock實(shí)現(xiàn)镐侯,并在Mock中return null夹孔。
如果只是想簡單的忽略異常,在2.0.11以上版本可用:
<dubbo:service interface="com.foo.BarService" mock="return null"/>
2.20、延遲暴露
如果你的服務(wù)需要Warmup時(shí)間搭伤,比如初始化緩存只怎,等待相關(guān)資源就位等,可以使用delay進(jìn)行延遲暴露怜俐。
延遲5秒暴露服務(wù):
<dubbo:servicedelay="5000"/>
延遲到Spring初始化完成后身堡,再暴露服務(wù):(基于Spring的ContextRefreshedEvent事件觸發(fā)暴露)
<dubbo:servicedelay="-1"/>
Spring2.x初始化死鎖問題
在Spring解析到<dubbo:service />時(shí),就已經(jīng)向外暴露了服務(wù)拍鲤,而Spring還在接著初始化其它Bean贴谎。如果這時(shí)有請求進(jìn)來,并且服務(wù)的實(shí)現(xiàn)類里有調(diào)用applicationContext.getBean()的用法季稳。
1. 請求線程的applicationContext.getBean()調(diào)用擅这,先同步singletonObjects判斷Bean是否存在,不存在就同步beanDefinitionMap進(jìn)行初始化景鼠,并再次同步singletonObjects寫入Bean實(shí)例緩存仲翎。
2. 而Spring初始化線程,因不需要判斷Bean的存在铛漓,直接同步beanDefinitionMap進(jìn)行初始化溯香,并同步singletonObjects寫入Bean實(shí)例緩存。
這樣就導(dǎo)致getBean線程浓恶,先鎖singletonObjects玫坛,再鎖beanDefinitionMap,再次鎖singletonObjects包晰。而Spring初始化線程湿镀,先鎖beanDefinitionMap,再鎖singletonObjects伐憾。
反向鎖導(dǎo)致線程死鎖勉痴,不能提供服務(wù),啟動不了塞耕。
規(guī)避辦法
1. 強(qiáng)烈建議不要在服務(wù)的實(shí)現(xiàn)類中有applicationContext.getBean()的調(diào)用,全部采用IoC注入的方式使用Spring的Bean嘴瓤。
2. 如果實(shí)在要調(diào)getBean()扫外,可以將Dubbo的配置放在Spring的最后加載。
3. 如果不想依賴配置順序廓脆,可以使用<dubbo:provider deplay=”-1” />筛谚,使Dubbo在Spring容器初始化完后,再暴露服務(wù)停忿。
4. 如果大量使用getBean()驾讲,相當(dāng)于已經(jīng)把Spring退化為工廠模式在用,可以將Dubbo的服務(wù)隔離單獨(dú)的Spring容器。
2.21吮铭、并發(fā)控制
限制com.foo.BarService的每個方法时迫,服務(wù)器端并發(fā)執(zhí)行(或占用線程池線程數(shù))不能超過10個:
<dubbo:service interface="com.foo.BarService" executes="10"/>
限制com.foo.BarService的sayHello方法,服務(wù)器端并發(fā)執(zhí)行(或占用線程池線程數(shù))不能超過10個:
<dubbo:service interface="com.foo.BarService">
<dubbo:method name="sayHello" executes="10"/>
</dubbo:service>
限制com.foo.BarService的每個方法谓晌,每客戶端并發(fā)執(zhí)行(或占用連接的請求數(shù))不能超過10個:
<dubbo:service interface="com.foo.BarService" actives="10"/>
或:
<dubbo:reference interface="com.foo.BarService" actives="10"/>
限制com.foo.BarService的sayHello方法掠拳,每客戶端并發(fā)執(zhí)行(或占用連接的請求數(shù))不能超過10個:
<dubbo:service interface="com.foo.BarService">
<dubbo:method name="sayHello" actives="10"/>
</dubbo:service>
或:
<dubbo:referenceinterface="com.foo.BarService">
<dubbo:methodname="sayHello"actives="10"/>
</dubbo:service>
如果<dubbo:service>和<dubbo:reference>都配了actives,<dubbo:reference>優(yōu)先纸肉。
配置服務(wù)的客戶端的loadbalance屬性為leastactive溺欧,此Loadbalance會調(diào)用并發(fā)數(shù)最小的Provider(Consumer端并發(fā)數(shù))。
<dubbo:referenceinterface="com.foo.BarService"loadbalance="leastactive"/>
或:
<dubbo:serviceinterface="com.foo.BarService"loadbalance="leastactive"/>
2.22柏肪、連接控制
限制服務(wù)器端接受的連接不能超過10個:(以連接在Server上姐刁,所以配置在Provider上)
<dubbo:provider protocol="dubbo" accepts="10"/>
<dubbo:protocol name="dubbo" accepts="10"/>
限制客戶端服務(wù)使用連接連接數(shù):(如果是長連接,比如Dubbo協(xié)議烦味,connections表示該服務(wù)對每個提供者建立的長連接數(shù))
<dubbo:referenceinterface="com.foo.BarService"connections="10"/>
或:
<dubbo:serviceinterface="com.foo.BarService"connections="10"/>
如果<dubbo:service>和<dubbo:reference>都配了connections聂使,<dubbo:reference>優(yōu)先。
2.23拐叉、延遲連接
延遲連接岩遗,用于減少長連接數(shù),當(dāng)有調(diào)用發(fā)起時(shí)凤瘦,再創(chuàng)建長連接宿礁。只對使用長連接的dubbo協(xié)議生效。
<dubbo:protocolname="dubbo"lazy="true"/>
2.24蔬芥、粘滯連接
粘滯連接用于有狀態(tài)服務(wù)梆靖,盡可能讓客戶端總是向同一提供者發(fā)起調(diào)用,除非該提供者掛了笔诵,再連另一臺返吻。粘滯連接將自動開啟延遲連接,以減少長連接數(shù)乎婿。
<dubbo:protocolname="dubbo"sticky="true"/>
2.25测僵、令牌驗(yàn)證
令牌驗(yàn)證的作用:
- 防止消費(fèi)者繞過注冊中心訪問提供者
- 在注冊中心控制權(quán)限,以決定要不要下發(fā)令牌給消費(fèi)者
- 注冊中心可靈活改變授權(quán)方式谢翎,而不需修改或升級提供者
可以全局設(shè)置開啟令牌驗(yàn)證:
<!--隨機(jī)token令牌捍靠,使用UUID生成-->
<dubbo:providerinterface="com.foo.BarService"token="true"/>
<!--固定token令牌,相當(dāng)于密碼-->
<dubbo:providerinterface="com.foo.BarService"token="123456"/>
也可在服務(wù)級別設(shè)置:
<!--隨機(jī)token令牌森逮,使用UUID生成-->
<dubbo:serviceinterface="com.foo.BarService"token="true"/>
<!--固定token令牌榨婆,相當(dāng)于密碼-->
<dubbo:serviceinterface="com.foo.BarService"token="123456"/>
還可在協(xié)議級別設(shè)置:
<!--隨機(jī)token令牌,使用UUID生成-->
<dubbo:protocolname="dubbo"token="true"/>
<!--固定token令牌褒侧,相當(dāng)于密碼-->
<dubbo:protocolname="dubbo"token="123456"/>