1本刽、沒有dubbo帶來什么問題?
- url太多無法維護(hù)管理
- 服務(wù)之間的調(diào)用url通過配置文件維護(hù),無法整理出服務(wù)之間的依賴關(guān)系坠陈,如果某個(gè)服務(wù)要重構(gòu)無法評(píng)估影響范圍
- 無法知道每個(gè)服務(wù)的調(diào)用量有多大连躏,想擴(kuò)容的話無法評(píng)估指標(biāo)剩岳,需要個(gè)監(jiān)控平臺(tái)來監(jiān)控調(diào)用量、響應(yīng)時(shí)間等入热。
2拍棕、Dubbo是什么?
dubbo是一個(gè)分布式的服務(wù)框架勺良,提供高性能以及透明化的RPC遠(yuǎn)程服務(wù)調(diào)用解決方法绰播,以及SOA服務(wù)治理方案。
遠(yuǎn)程通信尚困、集群容錯(cuò)蠢箩、服務(wù)的自動(dòng)發(fā)現(xiàn)、負(fù)載均衡
3事甜、架構(gòu)和角色
- Monitor啟動(dòng)后也是一個(gè)運(yùn)行在zookeeper下dubbo目錄里的一個(gè)服務(wù)谬泌,跟其他服務(wù)一樣,只是這個(gè)服務(wù)Consumer和Provider會(huì)定期向里面寫監(jiān)控?cái)?shù)據(jù)逻谦,數(shù)據(jù)存在zookeeper里呵萨。
- dubbo-admin :相當(dāng)于dubbo的后臺(tái)管理系統(tǒng),實(shí)際上就是對(duì)zookeeper節(jié)點(diǎn)的增刪改查來達(dá)到對(duì)整個(gè)dubbo的控制跨跨。
4潮峦、zookeeper 注冊(cè)中心
流程說明:
- 服務(wù)提供者啟動(dòng)時(shí): 向 /dubbo/com.foo.BarService/providers 目錄下寫入自己的 URL 地址
- 服務(wù)消費(fèi)者啟動(dòng)時(shí): 訂閱 /dubbo/com.foo.BarService/providers 目錄下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目錄下寫入自己的 URL 地址
- 監(jiān)控中心啟動(dòng)時(shí): 訂閱 /dubbo/com.foo.BarService 目錄下的所有提供者和消費(fèi)者 URL 地址勇婴。
支持以下功能:
- 當(dāng)提供者出現(xiàn)斷電等異常停機(jī)時(shí)忱嘹,注冊(cè)中心能自動(dòng)刪除提供者信息
- 當(dāng)注冊(cè)中心重啟時(shí),能自動(dòng)恢復(fù)注冊(cè)數(shù)據(jù)耕渴,以及訂閱請(qǐng)求
- 當(dāng)會(huì)話過期時(shí)拘悦,能自動(dòng)恢復(fù)注冊(cè)數(shù)據(jù),以及訂閱請(qǐng)求
5橱脸、集群容錯(cuò)
- Failover Cluster : 失敗重試(缺省方式)础米,重試其他服務(wù)器分苇,用于讀操作,可設(shè)置次數(shù)
- Failfast Cluster :快速失敗屁桑,只調(diào)用一次医寿,失敗立即報(bào)錯(cuò),用于新增操作
- Failsafe Cluster :失敗安全蘑斧,忽略異常靖秩,用于記日志
- Failback Cluster :失敗恢復(fù),后臺(tái)記錄失敗請(qǐng)求竖瘾,定時(shí)重發(fā)沟突,用于消息通知等操作
- Forking Cluster :同時(shí)請(qǐng)求多個(gè)服務(wù)器,只要一個(gè)成功即返回捕传,用于實(shí)時(shí)性較高的讀操作惠拭;
- Broadcast Cluster :廣播調(diào)用所有服務(wù)者,逐個(gè)調(diào)用庸论,任意一個(gè)報(bào)錯(cuò)則報(bào)錯(cuò)职辅;用于通知提供者更新本地緩存等。
6葡公、負(fù)載均衡
- Random LoadBalance : (缺使夼)隨機(jī)条霜,按權(quán)重設(shè)置隨機(jī)概率催什。
- RoundRobin LoadBalance : 輪詢,按公約后的權(quán)重設(shè)置輪詢比率宰睡。 存在慢的提供者累積請(qǐng)求的問題蒲凶,比如:第二臺(tái)機(jī)器很慢,但沒掛拆内,當(dāng)請(qǐng)求調(diào)到第二臺(tái)時(shí)就卡在那旋圆,久而久之,所有請(qǐng)求都卡在調(diào)到第二臺(tái)上麸恍。
- LeastActive LoadBalance : 最少活躍調(diào)用數(shù)灵巧,相同活躍數(shù)的隨機(jī),活躍數(shù)指調(diào)用前后計(jì)數(shù)差抹沪。使慢的提供者收到更少請(qǐng)求刻肄,因?yàn)樵铰奶峁┱叩恼{(diào)用前后計(jì)數(shù)差會(huì)越大。
- ConsistentHash LoadBalance : 一致性 Hash融欧,相同參數(shù)的請(qǐng)求總是發(fā)到同一提供者敏弃。當(dāng)某一臺(tái)提供者掛時(shí),原本發(fā)往該提供者的請(qǐng)求噪馏,基于虛擬節(jié)點(diǎn)麦到,平攤到其它提供者绿饵,不會(huì)引起劇烈變動(dòng)。
7瓶颠、線程模型
如果事件處理的邏輯能迅速完成拟赊,并且不會(huì)發(fā)起新的 IO 請(qǐng)求,比如只是在內(nèi)存中記個(gè)標(biāo)識(shí)步清,則直接在 IO 線程上處理更快要门,因?yàn)闇p少了線程池調(diào)度。
但如果事件處理邏輯較慢廓啊,或者需要發(fā)起新的 IO 請(qǐng)求欢搜,比如需要查詢數(shù)據(jù)庫,則必須派發(fā)到線程池谴轮,否則 IO 線程阻塞炒瘟,將導(dǎo)致不能接收其它請(qǐng)求。
如果用 IO 線程處理事件第步,又在事件處理過程中發(fā)起新的 IO 請(qǐng)求疮装,比如在連接事件中發(fā)起登錄請(qǐng)求,會(huì)報(bào)“可能引發(fā)死鎖”異常粘都,但不會(huì)真死鎖廓推。
因此,需要通過不同的派發(fā)策略和不同的線程池配置的組合來應(yīng)對(duì)不同的場(chǎng)景:
<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
Dispatcher
- all 所有消息都派發(fā)到線程池翩隧,包括請(qǐng)求樊展,響應(yīng),連接事件堆生,斷開事件专缠,心跳等。
- direct 所有消息都不派發(fā)到線程池淑仆,全部在 IO 線程上直接執(zhí)行涝婉。
- message 只有請(qǐng)求響應(yīng)消息派發(fā)到線程池,其它連接斷開事件蔗怠,心跳等消息墩弯,直接在 IO 線程上執(zhí)行。
- execution 只請(qǐng)求消息派發(fā)到線程池寞射,不含響應(yīng)渔工,響應(yīng)和其它連接斷開事件,心跳等消息怠惶,直接在 IO 線程上執(zhí)行涨缚。
- connection 在 IO 線程上,將連接斷開事件放入隊(duì)列,有序逐個(gè)執(zhí)行脓魏,其它消息派發(fā)到線程池兰吟。
ThreadPool
- fixed 固定大小線程池,啟動(dòng)時(shí)建立線程茂翔,不關(guān)閉混蔼,一直持有。(缺省)
- cached 緩存線程池珊燎,空閑一分鐘自動(dòng)刪除惭嚣,需要時(shí)重建。
- limited 可伸縮線程池悔政,但池中的線程數(shù)只會(huì)增長不會(huì)收縮晚吞。只增長不收縮的目的是為了避免收縮時(shí)突然來了大流量引起的性能問題。
- eager 優(yōu)先創(chuàng)建Worker線程池谋国。在任務(wù)數(shù)量大于corePoolSize但是小于maximumPoolSize時(shí)槽地,優(yōu)先創(chuàng)建Worker來處理任務(wù)。當(dāng)任務(wù)數(shù)量大于maximumPoolSize時(shí)芦瘾,將任務(wù)放入阻塞隊(duì)列中捌蚊。阻塞隊(duì)列充滿時(shí)拋出RejectedExecutionException。(相比于cached:cached在任務(wù)數(shù)量超過maximumPoolSize時(shí)直接拋出異常而不是將任務(wù)放入阻塞隊(duì)列)
8近弟、只訂閱缅糟、只注冊(cè)
-
只訂閱
為方便開發(fā)測(cè)試,經(jīng)常會(huì)在線下共用一個(gè)所有服務(wù)可用的注冊(cè)中心祷愉,這時(shí)窗宦,如果一個(gè)正在開發(fā)中的服務(wù)提供者注冊(cè),可能會(huì)影響消費(fèi)者不能正常運(yùn)行谣辞。
可以讓服務(wù)提供者開發(fā)方迫摔,只訂閱服務(wù)(開發(fā)的服務(wù)可能依賴其它服務(wù))沐扳,而不注冊(cè)正在開發(fā)的服務(wù)泥从,通過直連測(cè)試正在開發(fā)的服務(wù)。
<dubbo:registry address="10.20.153.10:9090" register="false" />
-
只注冊(cè)
如果有兩個(gè)鏡像環(huán)境沪摄,兩個(gè)注冊(cè)中心躯嫉,有一個(gè)服務(wù)只在其中一個(gè)注冊(cè)中心有部署,另一個(gè)注冊(cè)中心還沒來得及部署杨拐,而兩個(gè)注冊(cè)中心的其它應(yīng)用都需要依賴此服務(wù)祈餐,所以需要將服務(wù)同時(shí)注冊(cè)到兩個(gè)注冊(cè)中心,但卻不能讓此服務(wù)同時(shí)依賴兩個(gè)注冊(cè)中心的其他服務(wù)哄陶。這個(gè)時(shí)候帆阳,可以讓服務(wù)提供者方只注冊(cè)服務(wù)到另一注冊(cè)中心,而不從另一注冊(cè)中心訂閱服務(wù)屋吨。
禁用訂閱配置
<dubbo:registry id="hzRegistry" address="10.20.153.10:9090" /> <dubbo:registry id="qdRegistry" address="10.20.141.150:9090" subscribe="false" />
9蜒谤、配置多個(gè)傳輸協(xié)議
Dubbo 允許配置多協(xié)議山宾,在不同服務(wù)上支持不同協(xié)議或者同一服務(wù)上同時(shí)支持多種協(xié)議。
不同服務(wù)在性能上適用不同協(xié)議進(jìn)行傳輸鳍徽,比如大數(shù)據(jù)用短連接協(xié)議资锰,小數(shù)據(jù)大并發(fā)用長連接協(xié)議
<!-- 多協(xié)議配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />
<!-- 使用dubbo協(xié)議暴露服務(wù) -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
<!-- 使用rmi協(xié)議暴露服務(wù) -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" />
10、版本控制
當(dāng)一個(gè)接口實(shí)現(xiàn)阶祭,出現(xiàn)不兼容升級(jí)時(shí)绷杜,可以用版本號(hào)過渡,版本號(hào)不同的服務(wù)相互間不引用濒募。
可以按照以下的步驟進(jìn)行版本遷移:
1鞭盟、在低壓力時(shí)間段,先升級(jí)一半提供者為新版本
2瑰剃、再將所有消費(fèi)者升級(jí)為新版本
3懊缺、然后將剩下的一半提供者升級(jí)為新版本
新版本服務(wù)提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" />
新版本服務(wù)消費(fèi)者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />
如果不需要區(qū)分版本,可以按照以下的方式配置 [1]:
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
11培他、異步調(diào)用
基于 NIO 的非阻塞實(shí)現(xiàn)并行調(diào)用鹃两,客戶端不需要啟動(dòng)多線程即可完成并行調(diào)用多個(gè)遠(yuǎn)程服務(wù),相對(duì)多線程開銷較小舀凛。
在 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)用代碼:
// 此調(diào)用會(huì)立即返回null
fooService.findFoo(fooId);
// 拿到調(diào)用的Future引用俊扳,當(dāng)結(jié)果返回后,會(huì)被通知和設(shè)置到此Future
Future<Foo> fooFuture = RpcContext.getContext().getFuture();
// 此調(diào)用會(huì)立即返回null
barService.findBar(barId);
// 拿到調(diào)用的Future引用猛遍,當(dāng)結(jié)果返回后馋记,會(huì)被通知和設(shè)置到此Future
Future<Bar> barFuture = RpcContext.getContext().getFuture();
// 此時(shí)findFoo和findBar的請(qǐng)求同時(shí)在執(zhí)行,客戶端不需要啟動(dòng)多線程來支持并行懊烤,而是借助NIO的非阻塞完成
// 如果foo已返回梯醒,直接拿到返回值,否則線程wait住腌紧,等待foo返回后茸习,線程會(huì)被notify喚醒
Foo foo = fooFuture.get();
// 同理等待bar返回
Bar bar = barFuture.get();
// 如果foo需要5秒返回感挥,bar需要6秒返回碉纺,實(shí)際只需等6秒,即可獲取到foo和bar酸役,進(jìn)行接下來的處理浸遗。