Dubbo簡(jiǎn)介
首先,我理解的Dubbo剪况,從大的方向來看是單體應(yīng)用到分布式應(yīng)用過度期的一個(gè)產(chǎn)物,具體來說應(yīng)該是分布式應(yīng)用從早期的SOA到微服務(wù)過度的一個(gè)產(chǎn)物。
在編寫分布式場(chǎng)景下高并發(fā)俘枫、高擴(kuò)展的系統(tǒng)對(duì)技能的要求很高,因?yàn)檫@個(gè)過程會(huì)涉及到序列化/反序列化逮走、多線程鸠蚪、網(wǎng)絡(luò)編程、設(shè)計(jì)模式、性能優(yōu)化等眾多專業(yè)知識(shí)茅信。而Dubbo框架對(duì)這些專業(yè)知識(shí)做了更高層的抽象和封裝盾舌,提供了開箱即用的特性。所以換句話說Dubbo是為了解決大流量蘸鲸、高并發(fā)場(chǎng)景下提供高可用妖谴、提升系統(tǒng)性能的這樣一個(gè)服務(wù)治理方案,也是優(yōu)秀的RPC框架之一酌摇,因此被眾多公司采用并根據(jù)自己的業(yè)務(wù)實(shí)現(xiàn)擴(kuò)展膝舅。
Dubbo具體是一個(gè)什么?可不可以在稍微細(xì)化說明一下窑多?
上面有提到Dubbo是一個(gè)優(yōu)秀的RPC框架仍稀,是Java項(xiàng)目中卓越的框架之一。它提供了注冊(cè)中心機(jī)制埂息,解耦了服務(wù)方和消費(fèi)方動(dòng)態(tài)發(fā)現(xiàn)的問題技潘,并提供了高可靠能力,大量采用微內(nèi)核+富插件設(shè)計(jì)思想千康,包括框架自身核心特性都作為擴(kuò)展點(diǎn)實(shí)現(xiàn)享幽,提供了靈活的擴(kuò)展點(diǎn)能力。
關(guān)于Dubbo框架的架構(gòu)通過下面這張圖來先簡(jiǎn)單了解下拾弃,這是dubbo官方提供的值桩,我這邊重新畫了一下,也是為了加深自己的理解砸彬。如下:
1.服務(wù)提供者Provider啟動(dòng)時(shí)會(huì)向注冊(cè)中心把自己的元數(shù)據(jù)注冊(cè)上去(比如服務(wù)IP颠毙、端口及需要注冊(cè)的接口定義等信息);
2.服務(wù)消費(fèi)方Consumer在啟動(dòng)時(shí)會(huì)從注冊(cè)中心訂閱(第一次訂閱會(huì)拉取全量數(shù)據(jù))服務(wù)提供方的元數(shù)據(jù)砂碉;
3.而當(dāng)注冊(cè)中心數(shù)據(jù)發(fā)生變更時(shí)會(huì)推送給訂閱的Consumer(比如Provider某個(gè)節(jié)點(diǎn)Down掉了蛀蜜,又或者服務(wù)提供方進(jìn)行了擴(kuò)容,增加了節(jié)點(diǎn)增蹭。)滴某;
4.在Consumer獲取到元數(shù)據(jù)后,Consumer可以發(fā)起RPC調(diào)用(本質(zhì)其實(shí)是Socket通信+動(dòng)態(tài)代理這樣的一個(gè)實(shí)現(xiàn)機(jī)制)滋迈;
5.RPC調(diào)用前后會(huì)向監(jiān)控中心上報(bào)統(tǒng)計(jì)信息(比如并發(fā)數(shù)和調(diào)用接口)霎奢。
Dubbo特性總結(jié)
1.面向接口代理的改性能RPC調(diào)用
提供了高性能的基于代理的遠(yuǎn)程調(diào)用能力,服務(wù)以接口為粒度饼灿,為開發(fā)者屏蔽調(diào)用的遠(yuǎn)程細(xì)節(jié)幕侠。
2.服務(wù)自動(dòng)注冊(cè)與發(fā)現(xiàn)
支持多種注冊(cè)中心服務(wù),服務(wù)實(shí)例上下線實(shí)時(shí)感知(上圖中的第3步)碍彭。
3.運(yùn)行期流量調(diào)度
內(nèi)置條件晤硕、腳本等路由策略悼潭,通過配置不同的路由規(guī)則,輕松實(shí)現(xiàn)灰度發(fā)布舞箍、同機(jī)房?jī)?yōu)先等功能舰褪。
4.智能負(fù)載均衡
內(nèi)置多種負(fù)載均衡策略,智能感知下游節(jié)點(diǎn)健康狀況疏橄,顯著減少調(diào)用延遲占拍,提高系統(tǒng)吞吐量。
5.高度可擴(kuò)展能力
遵循微內(nèi)核+插件的設(shè)計(jì)思想捎迫,所有核心能力如Protocol晃酒、Transport、Serialization被設(shè)計(jì)為擴(kuò)展點(diǎn)立砸,平等對(duì)待內(nèi)置實(shí)現(xiàn)和第三方實(shí)現(xiàn)掖疮。(Dubbo SPI 擴(kuò)展點(diǎn)機(jī)制)
6.可視化的服務(wù)治理與運(yùn)維
提供了豐富服務(wù)治理、運(yùn)維工具(Dubbo Admin):隨時(shí)查詢服務(wù)元數(shù)據(jù)颗祝、服務(wù)簡(jiǎn)況狀態(tài)及調(diào)用統(tǒng)計(jì),實(shí)時(shí)下發(fā)路由策略恼布、調(diào)整配置參數(shù)螺戳。
Dubbo解決的問題
很多同學(xué)使用Dubbo有很長(zhǎng)一段時(shí)間,如果被問起為什么要使用Dubbo折汞,解決了什么問題倔幼?我們可能會(huì)隨口而出:通過RPC調(diào)用實(shí)現(xiàn)應(yīng)用間解耦,進(jìn)而實(shí)現(xiàn)將復(fù)雜應(yīng)用微服務(wù)化爽待; 保證了系統(tǒng)功能的專一性损同,進(jìn)而提高代碼或者業(yè)務(wù)功能的復(fù)用性; 分布式的架構(gòu)設(shè)計(jì)以及智能的負(fù)載均衡提升了我們系統(tǒng)的吞吐量鸟款,進(jìn)而提高了性能……沒錯(cuò)膏燃,是這樣的。但是除了這些可能也回答不出來什么了何什。這里關(guān)于Dubbo解決了什么問題做一下整理组哩,在被別人問道的時(shí)候心里也清楚,最關(guān)鍵的是為我們?cè)诤罄m(xù)的業(yè)務(wù)選型上可以做出正確的判斷处渣。
一開始就提到了單體應(yīng)用到分布式的演變伶贰,那么隨著業(yè)務(wù)的不斷擴(kuò)展,服務(wù)規(guī)模和架構(gòu)的不斷演進(jìn)罐栈,在大規(guī)模服務(wù)化之前黍衙,應(yīng)用可能只是通過Java 的 RMI協(xié)議 或Hession等工具實(shí)現(xiàn)簡(jiǎn)單地暴露和引用遠(yuǎn)程服務(wù),通過配置URL地址進(jìn)行調(diào)用荠诬,最后通過F5等硬件進(jìn)行負(fù)載均衡琅翻。那既然可以實(shí)現(xiàn)簡(jiǎn)單的遠(yuǎn)程調(diào)用位仁,為什么阿里還要投入這么大成本開發(fā)Dubbo呢,當(dāng)然肯定有必要的一些考量望迎,除了我剛剛提到的那點(diǎn)障癌,Dubbo主要解決以下幾個(gè)問題:
(1) 高性能、透明的RPC調(diào)用辩尊。只要涉及服務(wù)之間的通信涛浙,RPC就必不可。Dubbo可以讓我們像調(diào)用本地服務(wù)一樣簡(jiǎn)單的去調(diào)用遠(yuǎn)程服務(wù)摄欲,而不需要再代碼中顯示的指定遠(yuǎn)程調(diào)用轿亮。整個(gè)過程對(duì)上層開發(fā)者透明,Dubbo會(huì)自動(dòng)完成后續(xù)的所有操作胸墙,例如:負(fù)載均衡我注、路由、協(xié)議轉(zhuǎn)換迟隅、序列化等但骨。開發(fā)者只需要接收對(duì)應(yīng)的調(diào)用結(jié)果。
(2)服務(wù)的自動(dòng)注冊(cè)與發(fā)現(xiàn)智袭。當(dāng)服務(wù)越來越多時(shí)奔缠,服務(wù)URL配置管理變得非常困難,服務(wù)的注冊(cè)與發(fā)現(xiàn)已經(jīng)不可能由人工來管理吼野。此時(shí)需要一個(gè)注冊(cè)中心校哎,動(dòng)態(tài)的注冊(cè)和發(fā)現(xiàn)服務(wù),使服務(wù)的位置透明瞳步。Dubbo適配了多種注冊(cè)中心闷哆。
(3)自動(dòng)負(fù)載與容錯(cuò)。 當(dāng)服務(wù)越來越多時(shí)单起,F(xiàn)5一年負(fù)載均衡器的單點(diǎn)壓力也原來越大抱怔,Dubbo提供了完整的集群容錯(cuò)機(jī)制,可以實(shí)現(xiàn)軟件層面的負(fù)載均衡馏臭,依次降低硬件的壓力野蝇。Dubbo還提供了調(diào)用失敗的各種容錯(cuò)機(jī)制,如Failover括儒、Failfast绕沈、結(jié)果集合并等。
(4)動(dòng)態(tài)的流量調(diào)度帮寻。在應(yīng)用運(yùn)行時(shí)乍狐,某些服務(wù)節(jié)點(diǎn)可能因?yàn)橛布蛐枰獪p少負(fù)載或者某些節(jié)點(diǎn)需要人工手動(dòng)下線;又或者需要實(shí)現(xiàn)單元化的調(diào)用固逗、灰度功能浅蚪。通過Dubbo Admin管理控制臺(tái)藕帜,用戶可以在界面上動(dòng)態(tài)地調(diào)整每個(gè)服務(wù)的權(quán)重、路由規(guī)則惜傲、禁用/啟用洽故,實(shí)現(xiàn)運(yùn)行時(shí)的流量調(diào)度。
(5)依賴分析和調(diào)用統(tǒng)計(jì)
Dubbo可以介入第三方的APM做分布式鏈路追蹤與性能分析盗誊,或者使用已有的獨(dú)立監(jiān)控中心的調(diào)用次數(shù)及耗時(shí)时甚,我們可以通過這些數(shù)據(jù)反推系統(tǒng)容量,在合適的時(shí)候通過加機(jī)器進(jìn)行擴(kuò)容哈踱,并且可以預(yù)估需要添加多少臺(tái)機(jī)器荒适。
Dubbo總體分層
下面分享一下Dubbo的分層結(jié)構(gòu),每一層所做的事情开镣,讓我們對(duì)Dubbo有一個(gè)更進(jìn)一步的了解刀诬。
Dubbo總體分為業(yè)務(wù)層(Biz)、RPC層邪财、Remote三層陕壹。如果把每一層繼續(xù)細(xì)化,那一共可以分為10層树埠≌室可以參考下圖,圖中左邊是具體的分層弥奸,右邊是該層中比較重要的接口:
其中Service與Config兩層可以認(rèn)為是API層,主要提供給API使用者奋早,使用者無需關(guān)系底層的實(shí)現(xiàn)盛霎,只需要配置和完成業(yè)務(wù)代碼即可;后面所有層級(jí)合在一起耽装,可以認(rèn)為是SPI層愤炸,主要提供給擴(kuò)展者使用,即用戶可以基于Dubbo框架做定制性的二次開發(fā)掉奄,擴(kuò)展其功能规个。提供這個(gè)分層圖的主要目的是在大家學(xué)習(xí)期源碼的時(shí)候可以按照這個(gè)分層學(xué)習(xí)會(huì)清晰一下(我也在學(xué)習(xí)中)。
Dubbo核心組件
在學(xué)習(xí)任何一個(gè)框架或者是存儲(chǔ)等之前姓建,了解其核心組件是非常有必要的诞仓。Dubbo框架中分層代表了不同的邏輯實(shí)現(xiàn),他們是一個(gè)個(gè)組件速兔,這些組件構(gòu)成了整個(gè)Dubbo體系墅拭,在使用方角度更多接觸的可能是配置,更多底層構(gòu)件被抽象和隱藏了涣狗。Dubbo一個(gè)很大的特性和亮點(diǎn)便是提供了非常高的擴(kuò)展性谍婉,而這個(gè)恰恰得益于各個(gè)組件明確的分工設(shè)計(jì)舒憾,每個(gè)組件提供了靈活的擴(kuò)展點(diǎn),如下:
1.Service層
業(yè)務(wù)層穗熬。包括業(yè)務(wù)代碼接口與實(shí)現(xiàn)镀迂,即我們自己實(shí)現(xiàn)的業(yè)務(wù)代碼。
2.config層
配置層唤蔗。主要圍繞ServiceConfig(暴露的服務(wù)配置)和ReferenceConfig(引用的服務(wù)配置)兩個(gè)實(shí)現(xiàn)類展開探遵,初始化配置信息〈胍耄可以理解為該層管理整個(gè)Dubbo配置别凤。
3.proxy層
服務(wù)代理層。在Dubbo中领虹,無論生產(chǎn)者還是消費(fèi)者规哪,框架都會(huì)生成一個(gè)代理類,整個(gè)過程對(duì)上層是透明的塌衰。當(dāng)調(diào)用一個(gè)遠(yuǎn)程接口時(shí)诉稍,看起來就像調(diào)用本地接口一樣,代理層會(huì)自動(dòng)做遠(yuǎn)程調(diào)用并返回結(jié)果最疆,即讓業(yè)務(wù)層對(duì)遠(yuǎn)程調(diào)用完全無感杯巨。
4.registry層
注冊(cè)層。服務(wù)Dubbo框架的服務(wù)注冊(cè)與發(fā)現(xiàn)努酸。當(dāng)所有新的服務(wù)加入或者就服務(wù)下線時(shí)服爷,注冊(cè)中心都會(huì)感知并通知訂閱方。整個(gè)過程不需要人工參與获诈。
5.cluster層
集群容錯(cuò)層仍源。主要負(fù)責(zé)遠(yuǎn)程調(diào)用失敗時(shí)的容錯(cuò)策略(如失敗重試、快速失斕蛳选)笼踩;選擇具體調(diào)用節(jié)點(diǎn)時(shí)的復(fù)雜均衡策略(如隨機(jī)、一致性Hash等)亡嫌;特殊調(diào)用路徑的路由策略(如某個(gè)Consumer只會(huì)調(diào)用某個(gè)IP的Provider)嚎于。
6.monitor層
監(jiān)控層。復(fù)雜監(jiān)控統(tǒng)計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間等挟冠。
7.protocol層
遠(yuǎn)程調(diào)用層于购。封裝RPC調(diào)用的具體過程,Protocol是Invoker暴露(發(fā)布一個(gè)新功能讓別人調(diào)用)和引用(引用一個(gè)遠(yuǎn)程服務(wù)到本地)的主功能入口圃郊。它負(fù)責(zé)管理Invoker的整個(gè)生命周期价涝。Invoker是Dubbo哦核心模型,框架中所有其他模型都向它靠攏持舆,或者轉(zhuǎn)換成它色瘩,它代表一個(gè)可執(zhí)行體伪窖。
8.exchange層
信息交換層。建立Request-Response模型居兆,封裝請(qǐng)求響應(yīng)模式覆山,如吧同步請(qǐng)求轉(zhuǎn)化為一步請(qǐng)求。
9.transport層
網(wǎng)絡(luò)傳輸層泥栖。把網(wǎng)絡(luò)傳輸抽象為同一的接口簇宽,如Mina和Netty雖然接口不一樣,但是Dubbo在他們上面又封裝了統(tǒng)一的接口吧享。我們也可以根據(jù)其擴(kuò)展接口添加更多的網(wǎng)絡(luò)傳輸方式魏割。
10.Serialize層
序列化層。如果數(shù)據(jù)要通過網(wǎng)絡(luò)進(jìn)行發(fā)送钢颂,則需要先做做序列化钞它,變成二進(jìn)制流。序列化層負(fù)責(zé)管理整個(gè)框架網(wǎng)絡(luò)傳輸時(shí)的序列化/反序列化工作殊鞭。
Dubbo總體調(diào)用過程
或許目前有些同學(xué)還不能理解整個(gè)組件穿起來的工作工程遭垛,所以先以服務(wù)暴露/注冊(cè)為例子簡(jiǎn)單描述下。首先服務(wù)端(Provider服務(wù)提供者)在框架啟動(dòng)時(shí)操灿,會(huì)初始化服務(wù)實(shí)例锯仪,通過Proxy組件調(diào)用具體協(xié)議(Protocol),把服務(wù)端要暴露的接口封裝成Incoker(真實(shí)類型時(shí)AbstractProxyInvoker)趾盐,然后轉(zhuǎn)換成Exporter庶喜,這個(gè)時(shí)候框架會(huì)打開服務(wù)端口等,并記錄服務(wù)實(shí)例到內(nèi)存中救鲤,最后通過Registry吧服務(wù)元數(shù)據(jù)注冊(cè)到注冊(cè)中心(比如Zookeeper)溃卡。這就是服務(wù)端整個(gè)接口暴露的過程。關(guān)于這里提到了幾個(gè)組件蜒简,在做一下具體的說明:
(1)Proxy組件:我們知道Dubbo中只需喲引用一個(gè)接口就可以調(diào)用遠(yuǎn)程的服務(wù)。其實(shí)是Dubbo框架為我們生成了代理類漩仙,調(diào)用方法其實(shí)也是Proxy組件為我們生成的代理方法搓茬,最后會(huì)自動(dòng)發(fā)起遠(yuǎn)程/本地調(diào)用,并返回結(jié)果队他,整個(gè)過程對(duì)我們是完全透明的卷仑。
(2)Protocol:其實(shí)協(xié)議就是對(duì)數(shù)據(jù)的一種約定。它可以把我們對(duì)接口的配置通過不同的協(xié)議轉(zhuǎn)換成不同的Invoker對(duì)象麸折。例如:用DubboProtocol可以把XML文件中一個(gè)遠(yuǎn)程接口的配置轉(zhuǎn)換成一個(gè)DubboInvoker锡凝。
(3)Exporter:用于暴露到注冊(cè)中心的對(duì)象,它的內(nèi)部屬性持有了Invoker對(duì)象垢啼,我們可以認(rèn)為它是在Invoker上包了一層窜锯。
(4)Registry:把Exporter注冊(cè)到注冊(cè)中心张肾。
以上就是整個(gè)服務(wù)暴露的過程,如果Consumer在啟動(dòng)時(shí)在注冊(cè)中心訂閱了服務(wù)端的元數(shù)據(jù)(實(shí)例的IP锚扎、端口吞瞪、實(shí)例上暴露的接口信息),這樣Consumer就可以得到剛才暴露的服務(wù)了驾孔。
下面在來看一下Consumer調(diào)用服務(wù)的整個(gè)流程芍秆,這里只針對(duì)遠(yuǎn)程調(diào)用。Dubbo組件在調(diào)用流程中的角色及位置如下圖:
首先翠勉,調(diào)用者從Proxy開始妖啥,Proxy持有一個(gè)Invoker對(duì)象。然后觸發(fā)Invoker調(diào)用对碌。在Invoker調(diào)用中荆虱,需要使用Cluster負(fù)責(zé)容錯(cuò),比如失敗重試俭缓。Custer在調(diào)用之前會(huì)通過Directory獲取所有可以調(diào)用的遠(yuǎn)程服務(wù)Invoker列表(一個(gè)接口可能有多個(gè)實(shí)例/節(jié)點(diǎn)提供服務(wù))克伊。由于可以調(diào)用的服務(wù)有很多,此時(shí)如果用戶配置了路由規(guī)則(如制定某些方法只能調(diào)用某個(gè)節(jié)點(diǎn))华坦,那么Cluster還會(huì)根據(jù)路由規(guī)則將Invoker列表過濾一遍愿吹。
然后,存活下來的Invoker可能還會(huì)有很多惜姐,此時(shí)需要調(diào)用哪一個(gè)呢犁跪?這時(shí)候會(huì)通過loadBalance方位做負(fù)載均衡,最終選出一個(gè)可以調(diào)用的Invoker歹袁。這個(gè)Invoker在調(diào)用前又會(huì)經(jīng)過一個(gè)FilterChain(過濾器鏈)坷衍,這個(gè)FilterChain通常負(fù)責(zé)處理上下文、限流条舔、計(jì)數(shù)等枫耳。
接著,會(huì)使用Client做數(shù)據(jù)傳輸孟抗,如我們常見的Netty Client等(Socket通信)迁杨。傳輸之前肯定需要做一個(gè)私有協(xié)議的構(gòu)造,此時(shí)會(huì)用到Codec接口(主要作用是負(fù)責(zé)協(xié)議的編解碼)凄硼。在這之后便是序列化過程了(Serialication)铅协、然后傳輸?shù)椒?wù)提供端。服務(wù)提供者接受到數(shù)據(jù)包摊沉,也會(huì)使用Codec處理協(xié)議頭及一些包信息等狐史。處理完之后在對(duì)整個(gè)報(bào)文做反序列化處理。
隨后這個(gè)請(qǐng)求會(huì)被分配到線程池(TheadPool)中進(jìn)行處理,Server會(huì)處理這些請(qǐng)求骏全,根據(jù)請(qǐng)求查找賭贏的Exporter(它內(nèi)部持有了Invoker)苍柏。Invoker是被“封裝器模式”一層一層套了非常多的Filter的,因此在調(diào)用最終的實(shí)現(xiàn)類之前吟温,又會(huì)經(jīng)過一個(gè)服務(wù)提供者端的過濾器鏈序仙。
最終得到了具體的接口的真實(shí)實(shí)現(xiàn)并調(diào)用,在原路返回結(jié)果鲁豪。
這里的話整個(gè)RPC的調(diào)用過程就結(jié)束了孵延。
總結(jié)
寫這篇文章的目的在于希望對(duì)大家在學(xué)習(xí)Dubbo之前洗显,能夠?qū)ubbo的整個(gè)框架佑刷、組件及流程有一個(gè)相對(duì)清晰的認(rèn)識(shí)箍邮,這樣對(duì)后面的學(xué)習(xí)也會(huì)有很多的幫助。
更多個(gè)人博客:RelaxHeart網(wǎng) - Tec博客 - 歡迎來訪我的個(gè)人興趣分享網(wǎng)站