【转载保存】dubbo学习笔记
Dubbo
Dubbo簡介
首先,我理解的Dubbo,從大的方向來看是單體應(yīng)用到分布式應(yīng)用過度期的一個產(chǎn)物,具體來說應(yīng)該是分布式應(yīng)用從早期的SOA到微服務(wù)過度的一個產(chǎn)物。
在編寫分布式場景下高并發(fā)、高擴展的系統(tǒng)對技能的要求很高,因為這個過程會涉及到序列化/反序列化、多線程、網(wǎng)絡(luò)編程、設(shè)計模式、性能優(yōu)化等眾多專業(yè)知識。而Dubbo框架對這些專業(yè)知識做了更高層的抽象和封裝,提供了開箱即用的特性。所以換句話說Dubbo是為了解決大流量、高并發(fā)場景下提供高可用、提升系統(tǒng)性能的這樣一個服務(wù)治理方案,也是優(yōu)秀的RPC框架之一,因此被眾多公司采用并根據(jù)自己的業(yè)務(wù)實現(xiàn)擴展。
Dubbo具體是一個什么?可不可以在稍微細化說明一下?
上面有提到Dubbo是一個優(yōu)秀的RPC框架,是Java項目中卓越的框架之一。它提供了注冊中心機制,解耦了服務(wù)方和消費方動態(tài)發(fā)現(xiàn)的問題,并提供了高可靠能力,大量采用微內(nèi)核+富插件設(shè)計思想,包括框架自身核心特性都作為擴展點實現(xiàn),提供了靈活的擴展點能力。
關(guān)于Dubbo框架的架構(gòu)通過下面這張圖來先簡單了解下,這是dubbo官方提供的,我這邊重新畫了一下,也是為了加深自己的理解。如下:
1.服務(wù)提供者Provider啟動時會向注冊中心把自己的元數(shù)據(jù)注冊上去(比如服務(wù)IP、端口及需要注冊的接口定義等信息);
2.服務(wù)消費方Consumer在啟動時會從注冊中心訂閱(第一次訂閱會拉取全量數(shù)據(jù))服務(wù)提供方的元數(shù)據(jù);
3.而當注冊中心數(shù)據(jù)發(fā)生變更時會推送給訂閱的Consumer(比如Provider某個節(jié)點Down掉了,又或者服務(wù)提供方進行了擴容,增加了節(jié)點。);
4.在Consumer獲取到元數(shù)據(jù)后,Consumer可以發(fā)起RPC調(diào)用(本質(zhì)其實是Socket通信+動態(tài)代理這樣的一個實現(xiàn)機制);
5.RPC調(diào)用前后會向監(jiān)控中心上報統(tǒng)計信息(比如并發(fā)數(shù)和調(diào)用接口)。
Dubbo特性總結(jié)
1.面向接口代理的改性能RPC調(diào)用
提供了高性能的基于代理的遠程調(diào)用能力,服務(wù)以接口為粒度,為開發(fā)者屏蔽調(diào)用的遠程細節(jié)。
2.服務(wù)自動注冊與發(fā)現(xiàn)
支持多種注冊中心服務(wù),服務(wù)實例上下線實時感知(上圖中的第3步)。
3.運行期流量調(diào)度
內(nèi)置條件、腳本等路由策略,通過配置不同的路由規(guī)則,輕松實現(xiàn)灰度發(fā)布、同機房優(yōu)先等功能。
4.智能負載均衡
內(nèi)置多種負載均衡策略,智能感知下游節(jié)點健康狀況,顯著減少調(diào)用延遲,提高系統(tǒng)吞吐量。
5.高度可擴展能力
遵循微內(nèi)核+插件的設(shè)計思想,所有核心能力如Protocol、Transport、Serialization被設(shè)計為擴展點,平等對待內(nèi)置實現(xiàn)和第三方實現(xiàn)。(Dubbo SPI 擴展點機制)
6.可視化的服務(wù)治理與運維
提供了豐富服務(wù)治理、運維工具(Dubbo Admin):隨時查詢服務(wù)元數(shù)據(jù)、服務(wù)簡況狀態(tài)及調(diào)用統(tǒng)計,實時下發(fā)路由策略、調(diào)整配置參數(shù)。
Dubbo解決的問題
很多同學(xué)使用Dubbo有很長一段時間,如果被問起為什么要使用Dubbo,解決了什么問題?我們可能會隨口而出:通過RPC調(diào)用實現(xiàn)應(yīng)用間解耦,進而實現(xiàn)將復(fù)雜應(yīng)用微服務(wù)化; 保證了系統(tǒng)功能的專一性,進而提高代碼或者業(yè)務(wù)功能的復(fù)用性; 分布式的架構(gòu)設(shè)計以及智能的負載均衡提升了我們系統(tǒng)的吞吐量,進而提高了性能……沒錯,是這樣的。但是除了這些可能也回答不出來什么了。這里關(guān)于Dubbo解決了什么問題做一下整理,在被別人問道的時候心里也清楚,最關(guān)鍵的是為我們在后續(xù)的業(yè)務(wù)選型上可以做出正確的判斷。
一開始就提到了單體應(yīng)用到分布式的演變,那么隨著業(yè)務(wù)的不斷擴展,服務(wù)規(guī)模和架構(gòu)的不斷演進,在大規(guī)模服務(wù)化之前,應(yīng)用可能只是通過Java 的 RMI協(xié)議 或Hession等工具實現(xiàn)簡單地暴露和引用遠程服務(wù),通過配置URL地址進行調(diào)用,最后通過F5等硬件進行負載均衡。那既然可以實現(xiàn)簡單的遠程調(diào)用,為什么阿里還要投入這么大成本開發(fā)Dubbo呢,當然肯定有必要的一些考量,除了我剛剛提到的那點,Dubbo主要解決以下幾個問題:
(1) 高性能、透明的RPC調(diào)用。只要涉及服務(wù)之間的通信,RPC就必不可。Dubbo可以讓我們像調(diào)用本地服務(wù)一樣簡單的去調(diào)用遠程服務(wù),而不需要再代碼中顯示的指定遠程調(diào)用。整個過程對上層開發(fā)者透明,Dubbo會自動完成后續(xù)的所有操作,例如:負載均衡、路由、協(xié)議轉(zhuǎn)換、序列化等。開發(fā)者只需要接收對應(yīng)的調(diào)用結(jié)果。
(2)服務(wù)的自動注冊與發(fā)現(xiàn)。當服務(wù)越來越多時,服務(wù)URL配置管理變得非常困難,服務(wù)的注冊與發(fā)現(xiàn)已經(jīng)不可能由人工來管理。此時需要一個注冊中心,動態(tài)的注冊和發(fā)現(xiàn)服務(wù),使服務(wù)的位置透明。Dubbo適配了多種注冊中心。
(3)自動負載與容錯。 當服務(wù)越來越多時,F5一年負載均衡器的單點壓力也原來越大,Dubbo提供了完整的集群容錯機制,可以實現(xiàn)軟件層面的負載均衡,依次降低硬件的壓力。Dubbo還提供了調(diào)用失敗的各種容錯機制,如Failover、Failfast、結(jié)果集合并等。
(4)動態(tài)的流量調(diào)度。在應(yīng)用運行時,某些服務(wù)節(jié)點可能因為硬件原因需要減少負載或者某些節(jié)點需要人工手動下線;又或者需要實現(xiàn)單元化的調(diào)用、灰度功能。通過Dubbo Admin管理控制臺,用戶可以在界面上動態(tài)地調(diào)整每個服務(wù)的權(quán)重、路由規(guī)則、禁用/啟用,實現(xiàn)運行時的流量調(diào)度。
(5)依賴分析和調(diào)用統(tǒng)計
Dubbo可以介入第三方的APM做分布式鏈路追蹤與性能分析,或者使用已有的獨立監(jiān)控中心的調(diào)用次數(shù)及耗時,我們可以通過這些數(shù)據(jù)反推系統(tǒng)容量,在合適的時候通過加機器進行擴容,并且可以預(yù)估需要添加多少臺機器。
Dubbo總體分層
下面分享一下Dubbo的分層結(jié)構(gòu),每一層所做的事情,讓我們對Dubbo有一個更進一步的了解。
Dubbo總體分為業(yè)務(wù)層(Biz)、RPC層、Remote三層。如果把每一層繼續(xù)細化,那一共可以分為10層??梢詤⒖枷聢D,圖中左邊是具體的分層,右邊是該層中比較重要的接口:
其中Service與Config兩層可以認為是API層,主要提供給API使用者,使用者無需關(guān)系底層的實現(xiàn),只需要配置和完成業(yè)務(wù)代碼即可;后面所有層級合在一起,可以認為是SPI層,主要提供給擴展者使用,即用戶可以基于Dubbo框架做定制性的二次開發(fā),擴展其功能。提供這個分層圖的主要目的是在大家學(xué)習期源碼的時候可以按照這個分層學(xué)習會清晰一下(我也在學(xué)習中)。
Dubbo核心組件
在學(xué)習任何一個框架或者是存儲等之前,了解其核心組件是非常有必要的。Dubbo框架中分層代表了不同的邏輯實現(xiàn),他們是一個個組件,這些組件構(gòu)成了整個Dubbo體系,在使用方角度更多接觸的可能是配置,更多底層構(gòu)件被抽象和隱藏了。Dubbo一個很大的特性和亮點便是提供了非常高的擴展性,而這個恰恰得益于各個組件明確的分工設(shè)計,每個組件提供了靈活的擴展點,如下:
1.Service層
業(yè)務(wù)層。包括業(yè)務(wù)代碼接口與實現(xiàn),即我們自己實現(xiàn)的業(yè)務(wù)代碼。
2.config層
配置層。主要圍繞ServiceConfig(暴露的服務(wù)配置)和ReferenceConfig(引用的服務(wù)配置)兩個實現(xiàn)類展開,初始化配置信息。可以理解為該層管理整個Dubbo配置。
3.proxy層
服務(wù)代理層。在Dubbo中,無論生產(chǎn)者還是消費者,框架都會生成一個代理類,整個過程對上層是透明的。當調(diào)用一個遠程接口時,看起來就像調(diào)用本地接口一樣,代理層會自動做遠程調(diào)用并返回結(jié)果,即讓業(yè)務(wù)層對遠程調(diào)用完全無感。
4.registry層
注冊層。服務(wù)Dubbo框架的服務(wù)注冊與發(fā)現(xiàn)。當所有新的服務(wù)加入或者就服務(wù)下線時,注冊中心都會感知并通知訂閱方。整個過程不需要人工參與。
5.cluster層
集群容錯層。主要負責遠程調(diào)用失敗時的容錯策略(如失敗重試、快速失敗);選擇具體調(diào)用節(jié)點時的復(fù)雜均衡策略(如隨機、一致性Hash等);特殊調(diào)用路徑的路由策略(如某個Consumer只會調(diào)用某個IP的Provider)。
6.monitor層
監(jiān)控層。復(fù)雜監(jiān)控統(tǒng)計調(diào)用次數(shù)和調(diào)用時間等。
7.protocol層
遠程調(diào)用層。封裝RPC調(diào)用的具體過程,Protocol是Invoker暴露(發(fā)布一個新功能讓別人調(diào)用)和引用(引用一個遠程服務(wù)到本地)的主功能入口。它負責管理Invoker的整個生命周期。Invoker是Dubbo哦核心模型,框架中所有其他模型都向它靠攏,或者轉(zhuǎn)換成它,它代表一個可執(zhí)行體。
8.exchange層
信息交換層。建立Request-Response模型,封裝請求響應(yīng)模式,如吧同步請求轉(zhuǎn)化為一步請求。
9.transport層
網(wǎng)絡(luò)傳輸層。把網(wǎng)絡(luò)傳輸抽象為同一的接口,如Mina和Netty雖然接口不一樣,但是Dubbo在他們上面又封裝了統(tǒng)一的接口。我們也可以根據(jù)其擴展接口添加更多的網(wǎng)絡(luò)傳輸方式。
10.Serialize層
序列化層。如果數(shù)據(jù)要通過網(wǎng)絡(luò)進行發(fā)送,則需要先做做序列化,變成二進制流。序列化層負責管理整個框架網(wǎng)絡(luò)傳輸時的序列化/反序列化工作。
Dubbo總體調(diào)用過程
或許目前有些同學(xué)還不能理解整個組件穿起來的工作工程,所以先以服務(wù)暴露/注冊為例子簡單描述下。首先服務(wù)端(Provider服務(wù)提供者)在框架啟動時,會初始化服務(wù)實例,通過Proxy組件調(diào)用具體協(xié)議(Protocol),把服務(wù)端要暴露的接口封裝成Incoker(真實類型時AbstractProxyInvoker),然后轉(zhuǎn)換成Exporter,這個時候框架會打開服務(wù)端口等,并記錄服務(wù)實例到內(nèi)存中,最后通過Registry吧服務(wù)元數(shù)據(jù)注冊到注冊中心(比如Zookeeper)。這就是服務(wù)端整個接口暴露的過程。關(guān)于這里提到了幾個組件,在做一下具體的說明:
(1)Proxy組件:我們知道Dubbo中只需喲引用一個接口就可以調(diào)用遠程的服務(wù)。其實是Dubbo框架為我們生成了代理類,調(diào)用方法其實也是Proxy組件為我們生成的代理方法,最后會自動發(fā)起遠程/本地調(diào)用,并返回結(jié)果,整個過程對我們是完全透明的。
(2)Protocol:其實協(xié)議就是對數(shù)據(jù)的一種約定。它可以把我們對接口的配置通過不同的協(xié)議轉(zhuǎn)換成不同的Invoker對象。例如:用DubboProtocol可以把XML文件中一個遠程接口的配置轉(zhuǎn)換成一個DubboInvoker。
(3)Exporter:用于暴露到注冊中心的對象,它的內(nèi)部屬性持有了Invoker對象,我們可以認為它是在Invoker上包了一層。
(4)Registry:把Exporter注冊到注冊中心。
以上就是整個服務(wù)暴露的過程,如果Consumer在啟動時在注冊中心訂閱了服務(wù)端的元數(shù)據(jù)(實例的IP、端口、實例上暴露的接口信息),這樣Consumer就可以得到剛才暴露的服務(wù)了。
下面在來看一下Consumer調(diào)用服務(wù)的整個流程,這里只針對遠程調(diào)用。Dubbo組件在調(diào)用流程中的角色及位置如下圖:
首先,調(diào)用者從Proxy開始,Proxy持有一個Invoker對象。然后觸發(fā)Invoker調(diào)用。在Invoker調(diào)用中,需要使用Cluster負責容錯,比如失敗重試。Custer在調(diào)用之前會通過Directory獲取所有可以調(diào)用的遠程服務(wù)Invoker列表(一個接口可能有多個實例/節(jié)點提供服務(wù))。由于可以調(diào)用的服務(wù)有很多,此時如果用戶配置了路由規(guī)則(如制定某些方法只能調(diào)用某個節(jié)點),那么Cluster還會根據(jù)路由規(guī)則將Invoker列表過濾一遍。
然后,存活下來的Invoker可能還會有很多,此時需要調(diào)用哪一個呢?這時候會通過loadBalance方位做負載均衡,最終選出一個可以調(diào)用的Invoker。這個Invoker在調(diào)用前又會經(jīng)過一個FilterChain(過濾器鏈),這個FilterChain通常負責處理上下文、限流、計數(shù)等。
接著,會使用Client做數(shù)據(jù)傳輸,如我們常見的Netty Client等(Socket通信)。傳輸之前肯定需要做一個私有協(xié)議的構(gòu)造,此時會用到Codec接口(主要作用是負責協(xié)議的編解碼)。在這之后便是序列化過程了(Serialication)、然后傳輸?shù)椒?wù)提供端。服務(wù)提供者接受到數(shù)據(jù)包,也會使用Codec處理協(xié)議頭及一些包信息等。處理完之后在對整個報文做反序列化處理。
隨后這個請求會被分配到線程池(TheadPool)中進行處理,Server會處理這些請求,根據(jù)請求查找賭贏的Exporter(它內(nèi)部持有了Invoker)。Invoker是被“封裝器模式”一層一層套了非常多的Filter的,因此在調(diào)用最終的實現(xiàn)類之前,又會經(jīng)過一個服務(wù)提供者端的過濾器鏈。
最終得到了具體的接口的真實實現(xiàn)并調(diào)用,在原路返回結(jié)果。
這里的話整個RPC的調(diào)用過程就結(jié)束了。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的【转载保存】dubbo学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转载保存】Jsoup解析html常用方
- 下一篇: 常见压缩算法学习