7000字+22張圖探秘Dubbo一次RPC調(diào)用的核心流程
今天繼續(xù)探秘系列,扒一扒一次RPC請(qǐng)求在Dubbo中經(jīng)歷的核心流程。
本文是基于Dubbo3.x版本進(jìn)行講解
一個(gè)簡(jiǎn)單的Demo
這里還是老樣子,為了保證文章的完整性和連貫性,方便那些沒(méi)有使用過(guò)的小伙伴更加容易接受文章的內(nèi)容,這里快速講一講Dubbo一個(gè)簡(jiǎn)單的Demo。
在Dubbo中RPC調(diào)用過(guò)程中主要分為以下兩個(gè)角色:
- 服務(wù)提供者:提供一個(gè)接口給消費(fèi)者遠(yuǎn)程調(diào)用。
- 服務(wù)消費(fèi)者:調(diào)用生產(chǎn)者提供的接口。
于是一個(gè)簡(jiǎn)單的Dubbo示例工程就如下所示:
示例工程的創(chuàng)建步驟、使用配置、第三方的依賴等詳細(xì)內(nèi)容可參考官網(wǎng):https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/spring-boot/
接口層,提供者消費(fèi)者都需要依賴,服務(wù)提供者實(shí)現(xiàn),服務(wù)消費(fèi)者調(diào)用
圖片
服務(wù)提供者單獨(dú)一個(gè)工程,實(shí)現(xiàn)DemoService接口,通過(guò)@DubboService表明提供DemoService這個(gè)服務(wù)。
圖片
服務(wù)消費(fèi)者單獨(dú)一個(gè)工程,這里使用單元測(cè)試,通過(guò)@DubboReference注解表明消費(fèi)DemoService這個(gè)服務(wù)接口。
圖片
啟動(dòng)服務(wù)提供者,運(yùn)行消費(fèi)者單元測(cè)試,結(jié)果如下:
成功實(shí)現(xiàn)遠(yuǎn)程服務(wù)調(diào)用
服務(wù)提供者暴露
所謂的服務(wù)提供者暴露,主要就是指在項(xiàng)目啟動(dòng)時(shí)服務(wù)提供者去做的兩件事
第一件事就是,由于需要對(duì)外提供調(diào)用服務(wù),接受消費(fèi)者的請(qǐng)求
所以在啟動(dòng)時(shí)需要根據(jù)使用協(xié)議,以及協(xié)議對(duì)應(yīng)的端口啟動(dòng)一個(gè)對(duì)應(yīng)的服務(wù)
就拿前面DemoService來(lái)舉例,由于@DubboService注解沒(méi)有指定任何信息
所以DemoService默認(rèn)就是使用Dubbo框架自己寫(xiě)的通信協(xié)議,也就是Dubbo協(xié)議,這個(gè)協(xié)議默認(rèn)使用的端口就是20880
之后如果要調(diào)用DemoService的方法時(shí),就可以按照Dubbo協(xié)議要求組裝數(shù)據(jù)格式
向20880端口發(fā)送請(qǐng)求,從而就實(shí)現(xiàn)遠(yuǎn)程服務(wù)調(diào)用,如下圖所示:
圖片
當(dāng)然除了默認(rèn)的Dubbo協(xié)議之外,Dubbo還支持其它的通信協(xié)議,后面會(huì)詳細(xì)介紹:
雖然第一件事成功讓接口可以對(duì)外提供訪問(wèn),但是對(duì)于消費(fèi)者來(lái)說(shuō),它其實(shí)還是無(wú)法訪問(wèn)接口。
因?yàn)橄M(fèi)者并不知道接口使用的是哪個(gè)通信協(xié)議、端口,也不知道接口所在的服務(wù)器的ip。
于是,在啟動(dòng)時(shí)就會(huì)去做第二件事。
第二件事是將每個(gè)接口的詳細(xì)信息,包括接口的全限定名、方法名稱、方法參數(shù)、服務(wù)器的ip、端口、通信協(xié)議等等按照一定的格式組裝好。
存放到元數(shù)據(jù)中心和服務(wù)提供者本地緩存中。
注意這是3.x版本時(shí)的存儲(chǔ)情況,跟2.x有點(diǎn)不同。并且元數(shù)據(jù)中心其實(shí)就是使用的Nacos或者Zookeeper來(lái)實(shí)現(xiàn)的,所以你可以認(rèn)為就是存儲(chǔ)在Nacos或者Zookeeper中。
之后消費(fèi)者需要調(diào)用接口時(shí),就可以從元數(shù)據(jù)中心或者服務(wù)提供者本地緩存中獲取到接口的詳細(xì)信息(具體從哪取決于配置,默認(rèn)是從本地緩存中獲取)。
圖片
這里你肯定有疑問(wèn)消費(fèi)者是如何從服務(wù)提供者本地緩存獲取,這就涉及到Dubbo3.x應(yīng)用級(jí)服務(wù)注冊(cè)的邏輯了,所以就不詳細(xì)展開(kāi)了,不過(guò)立個(gè)flag,如果本篇文章點(diǎn)贊達(dá)到38個(gè),就再來(lái)一篇,單獨(dú)講一講Dubbo3.x應(yīng)用級(jí)服務(wù)注冊(cè)的原理。
當(dāng)需要發(fā)起調(diào)用時(shí),就可以按照接口使用的協(xié)議組裝數(shù)據(jù),向接口所在的服務(wù)器ip和端口發(fā)送請(qǐng)求。
所以總的來(lái)說(shuō),服務(wù)提供者暴露主要就是這兩件事:
- 根據(jù)接口使用協(xié)議和端口開(kāi)啟服務(wù),對(duì)外提供接口訪問(wèn)。
- 將當(dāng)前服務(wù)支持的接口,以及每個(gè)接口使用的協(xié)議、端口、服務(wù)器ip等信息存到元數(shù)據(jù)中心或者本地緩存,供消費(fèi)者獲取。
消費(fèi)者引用
前面提到,如果消費(fèi)者想引用遠(yuǎn)程服務(wù),可以通過(guò)@DubboReference注解觸發(fā)引用的邏輯。
消費(fèi)者引用也會(huì)去做兩件事。
第一件事我們都知道,那就是創(chuàng)建接口的動(dòng)態(tài)代理。
由于消費(fèi)者使用的DubboService是一個(gè)接口,所以會(huì)給DubboService創(chuàng)建一個(gè)動(dòng)態(tài)代理。
這個(gè)動(dòng)態(tài)代理最終也會(huì)發(fā)送請(qǐng)求RPC請(qǐng)求。
Dubbo支持兩種動(dòng)態(tài)搭理生成方式:
- JDK動(dòng)態(tài)搭理
- Javassist動(dòng)態(tài)生成字節(jié)碼
默認(rèn)使用的Javassist動(dòng)態(tài)生成字節(jié)碼的方式。
除了創(chuàng)建動(dòng)態(tài)搭理之外,還會(huì)去獲取服務(wù)提供者的接口詳細(xì)信息。
上面一節(jié)說(shuō)了,可以從元數(shù)據(jù)中心或者是服務(wù)提供者本地緩存中獲取到。
當(dāng)獲取到接口詳情數(shù)據(jù)之后,會(huì)為之后的RPC調(diào)用做一些準(zhǔn)備工作。
比如如果接口使用的是Dubbo通信協(xié)議的話,準(zhǔn)備工作就是消費(fèi)者會(huì)跟服務(wù)提供者機(jī)器建立長(zhǎng)連接。
好了,到這里我們就把服務(wù)者暴露和消費(fèi)者引用都講完了。
接下來(lái)就會(huì)進(jìn)入本文的主題,一次RPC調(diào)用,也就是調(diào)用動(dòng)態(tài)代理之后在Dubbo中會(huì)經(jīng)歷哪些環(huán)節(jié)。
參數(shù)封裝
熟悉JDK動(dòng)態(tài)代理的同學(xué)肯定知道,當(dāng)調(diào)用動(dòng)態(tài)代理方法時(shí),最終會(huì)走到InvocationHandler的實(shí)現(xiàn)。
圖片
在Dubbo中,調(diào)用消費(fèi)者動(dòng)態(tài)代理的時(shí)候,不論是JDK動(dòng)態(tài)代理還是使用Javassist方式生成動(dòng)態(tài)代理。
最終都會(huì)走到InvokerInvocationHandler這個(gè)InvocationHandler的實(shí)現(xiàn)。
圖片
所以這個(gè)整個(gè)RPC調(diào)用的起點(diǎn)就是invoke方法的實(shí)現(xiàn);
圖片
如圖所示,首先將RPC調(diào)用的接口、方法名、參數(shù)封裝到RpcInvocation中。
接著會(huì)走到下面這行代碼。
invoker.invoke(rpcInvocation)
而這看似簡(jiǎn)簡(jiǎn)單單一行代碼就會(huì)觸發(fā)RPC調(diào)用的整個(gè)核心流程:
ClusterFilter過(guò)濾
當(dāng)參數(shù)封裝完成之后,接下來(lái)就會(huì)走到ClusterFilter過(guò)濾環(huán)節(jié)。
圖片
ClusterFilter本質(zhì)是一種責(zé)任鏈模式,是Dubbo提供的一個(gè)重要擴(kuò)展點(diǎn)。
通過(guò)實(shí)現(xiàn)invoke方法對(duì)請(qǐng)求進(jìn)行自定義預(yù)處理操作。
Dubbo默認(rèn)提供了幾種實(shí)現(xiàn)。
圖片
比如就拿MonitorClusterFilter來(lái)說(shuō):
這個(gè)實(shí)現(xiàn)主要是去統(tǒng)計(jì)每個(gè)接口的每個(gè)方法調(diào)用成功多少次,調(diào)用失敗多少次等等調(diào)用的信息。
除了默認(rèn)實(shí)現(xiàn)之外,很多我們熟悉的一些框架也是通過(guò)這個(gè)擴(kuò)展點(diǎn)跟Dubbo進(jìn)行整合的。
就比如常見(jiàn)的流控框架Sentinel!
圖片
集群調(diào)用邏輯決策
當(dāng)走完ClusterFilter之后,接下來(lái)就會(huì)來(lái)到集群調(diào)用邏輯決策的環(huán)節(jié)。
這個(gè)集群調(diào)用邏輯決策是什么意思呢?
在實(shí)際生產(chǎn)環(huán)境中,一般服務(wù)都會(huì)以集群的方式來(lái)部署。
這就會(huì)產(chǎn)生一個(gè)問(wèn)題,面對(duì)多服務(wù)情況下,怎么去調(diào)用?
圖片
舉個(gè)例子,按圖上所示,有三個(gè)服務(wù)
那么集群調(diào)用邏輯就是去決定。
應(yīng)該每個(gè)服務(wù)都去調(diào)用一次,還是只去調(diào)用其中一個(gè)?
如果只調(diào)用其中一個(gè),比如調(diào)用服務(wù)1,如果失敗了,那么此時(shí)是直接拋異常還是選擇繼續(xù)去調(diào)用服務(wù)2,還是做其它的事?
所以集群調(diào)用邏輯就是解決多服務(wù)實(shí)例下,應(yīng)該怎樣合理地調(diào)用服務(wù)實(shí)例。
Dubbo提供了以下幾種集群調(diào)用邏輯:
- 廣播,也就是每個(gè)服務(wù)都調(diào)用(broadcast)。
- 調(diào)用前會(huì)去判斷服務(wù)是不是可用,如果可用,那么就直接進(jìn)行調(diào)用(available)。
- 調(diào)用失敗,會(huì)開(kāi)啟定時(shí)任務(wù)進(jìn)行重試調(diào)用,最大重試3次(failback)。
- 調(diào)用失敗就直接拋出異常(failfast)。
- 調(diào)用失敗直接調(diào)用其它服務(wù)進(jìn)行重試,故障轉(zhuǎn)移(failover)。
- 調(diào)用失敗不會(huì)拋異常,而是直接返回(failsafe)。
- 同時(shí)調(diào)用指定個(gè)數(shù)的服務(wù),直接最快返回結(jié)果當(dāng)做這個(gè)調(diào)用的結(jié)果(forking)。
- 調(diào)用每個(gè)服務(wù),合并服務(wù)返回的數(shù)據(jù)作為調(diào)用的結(jié)果,結(jié)果怎么合并需要我們自定義相關(guān)邏輯(mergeable)。
在默認(rèn)情況下使用的就是failover,也就是出現(xiàn)異常時(shí)會(huì)調(diào)用其它的服務(wù)再返回結(jié)果。
當(dāng)然我們也可以按照如下的方式指定調(diào)用策略。
圖片
路由策略
上一節(jié)是解決集群中眾多實(shí)例時(shí)應(yīng)該如何調(diào)用的問(wèn)題。
而路由策略其實(shí)是選擇允許調(diào)用哪些服務(wù)實(shí)例。
因?yàn)椴⒉皇撬械姆?wù)實(shí)例都符合調(diào)用要求。
什么意思呢?
舉個(gè)例子,現(xiàn)在有個(gè)灰度發(fā)布的場(chǎng)景。
假設(shè)所有的服務(wù)都處于同一套環(huán)境中,有一群機(jī)器運(yùn)行者之前正式版本的服務(wù),有一群機(jī)器運(yùn)行著灰度版本的服務(wù),如下圖所示:
圖片
那么對(duì)于處于灰度的消費(fèi)者肯定要調(diào)用處于灰度的服務(wù)提供者。
但是由于在同一套環(huán)境,那么處于灰度的消費(fèi)者其實(shí)是能獲取到處于之前正式環(huán)境的服務(wù)接口信息。
如果就這么直接調(diào)用,那么處于灰度的消費(fèi)者就可能調(diào)用非灰度的服務(wù)提供者。
這肯定是不允許的。
所以必須在調(diào)用前過(guò)濾掉非灰度發(fā)布的服務(wù)。
而這種情況就可以交給路由來(lái)過(guò)濾。
假設(shè)如果想做到灰度區(qū)分,可以使用Dubbo提供了一種叫tag的路由策略。
灰度的服務(wù)提供者可以指定自己的tag屬性為gray(灰色的意思),如下所示:
圖片
而對(duì)于處于灰度的消費(fèi)者,只需要指定消費(fèi)tag為gray的服務(wù)提供者,如下所示:
圖片
這樣在真正調(diào)用前就會(huì)通過(guò)tag路由的方式過(guò)濾出處于灰度的服務(wù)提供者。
所以集群調(diào)用邏輯所能使用的服務(wù)實(shí)例只能是經(jīng)過(guò)路由策略選擇出來(lái)。
圖片
除了tag路由策略之外,Dubbo還提供了以下幾種路由策略:
- 條件路由,可以指定某些條件下可以調(diào)用哪些服務(wù)實(shí)例。
- 腳本路由,可以寫(xiě)一段JavaScript腳本,更加靈活地選擇哪些服務(wù)實(shí)例。
順帶說(shuō)一句,這個(gè)路由功能可以用來(lái)實(shí)現(xiàn)一個(gè)更高大上的功能,叫做流量管控。
負(fù)載均衡
所謂的負(fù)載均衡就是說(shuō),面對(duì)多個(gè)服務(wù)實(shí)例,我們應(yīng)該按照何種算法選擇一個(gè)供我們調(diào)用。
Dubbo提供了以下幾種負(fù)載均衡策略:
- 隨機(jī)(random),隨機(jī)選擇一個(gè)
- 輪詢(roundrobin),每次調(diào)用按照順序選擇一個(gè)
- 最少活躍優(yōu)先(leastactive),優(yōu)先選擇被最少調(diào)用的服務(wù)
- 最短響應(yīng)優(yōu)先(shortestresponse),優(yōu)先選擇響應(yīng)時(shí)間斷的服務(wù)調(diào)用
- 一致性Hash(consistenthash)
在沒(méi)有指定的情況下,默認(rèn)使用的就是隨機(jī)(random)算法:
如果想進(jìn)行修改,可以按照如下方式:
圖片
這里你肯定有疑問(wèn);
這個(gè)負(fù)載均衡和集群調(diào)用策略有什么關(guān)系?感覺(jué)這兩者有點(diǎn)像,又感覺(jué)這兩者有點(diǎn)沖突。
其實(shí)集群調(diào)用策略的優(yōu)先級(jí)會(huì)大于負(fù)載均衡。
比如說(shuō)如果集群調(diào)用策略選擇默認(rèn),也就是故障轉(zhuǎn)移(failover)。
那么對(duì)于路由策略過(guò)濾出來(lái)的服務(wù)實(shí)例,會(huì)根據(jù)負(fù)載均衡算法選擇一個(gè)進(jìn)行調(diào)用。
但是如果集群調(diào)用策略選擇的是廣播調(diào)用(broadcast)。
那么對(duì)于路由策略過(guò)濾出來(lái)的服務(wù)實(shí)例,實(shí)際上每個(gè)都需要去調(diào)用。
所以此時(shí)壓根不需要走負(fù)載均衡策略,因?yàn)闆](méi)有意義,即使你配置了,也不會(huì)生效。
所以需不需要負(fù)載均衡這件事,取決于使用什么集群調(diào)用策略。
總的來(lái)說(shuō),集群調(diào)用策略、路由策略、負(fù)載均衡策略它們一步一步去決定本次RPC調(diào)用具體應(yīng)該調(diào)用哪個(gè)或者哪些服務(wù)實(shí)例:
三者關(guān)系入下圖所示:
圖片
Filter過(guò)濾
經(jīng)過(guò)上面的幾步,終于知道本地RPC請(qǐng)求需要請(qǐng)求哪個(gè)或者哪些具體的服務(wù)實(shí)例。
接下來(lái)只需要向?qū)?yīng)的服務(wù)實(shí)例發(fā)送請(qǐng)求就可以了。
不過(guò)在發(fā)送請(qǐng)求前,Dubbo還預(yù)留了一個(gè)擴(kuò)展點(diǎn),叫做Filter。
本質(zhì)也是一種責(zé)任鏈模式。
圖片
通過(guò)Filter,我們可以在RPC調(diào)用前對(duì)整個(gè)請(qǐng)求再進(jìn)行自定義擴(kuò)展。
這里你肯定又會(huì)有一個(gè)疑問(wèn)?
Filter和前面提到的ClusterFilter有什么區(qū)別?
的確它兩真的很像,甚至都繼承同一個(gè)接口BaseFilter,但是它兩還有一些區(qū)別。
第一點(diǎn),兩者作用時(shí)機(jī)不同。
通過(guò)講解順序我們可以看出,ClusterFilter作用在路由和負(fù)載均衡前,而Filter在路由和負(fù)載均衡后。
所以只要我們?cè)敢?,我們可以通過(guò)ClusterFilter去影響后面的路由和負(fù)載均衡,而Filter是做不到的。
第二點(diǎn)就是Filter是跟服務(wù)實(shí)例走的。
在調(diào)用每個(gè)服務(wù)實(shí)例之前,F(xiàn)ilter一定會(huì)都會(huì)重新調(diào)用一遍。
比如假設(shè)這次RPC最終需要選擇調(diào)用兩個(gè)服務(wù)實(shí)例,那么Filter會(huì)走兩遍。
但是對(duì)于ClusterFilter,在整個(gè)調(diào)用過(guò)程中它僅僅只會(huì)執(zhí)行一次。
所以官方也是建議,在無(wú)特殊情況下,優(yōu)先選擇使用ClusterFilter而不是Filter。
到這,畫(huà)一張圖總結(jié)一下前面整個(gè)調(diào)用環(huán)節(jié)用。
圖片
通信協(xié)議
當(dāng)Filter責(zé)任鏈走完之后,接下來(lái)就到了向服務(wù)實(shí)例發(fā)送請(qǐng)求的時(shí)候了。
一旦涉及到服務(wù)與服務(wù)之間的調(diào)用,那么就離不開(kāi)通信協(xié)議。
所謂的通信協(xié)議,講的簡(jiǎn)單點(diǎn)就是發(fā)送方把需要發(fā)送的數(shù)據(jù)按照一定的格式組裝好之后再發(fā)送給接收方。
Dubbo需要發(fā)送數(shù)據(jù)包括調(diào)用但不限于接口全限定名、調(diào)用的方法名、調(diào)用參數(shù)等等。
而接收方在獲取到數(shù)據(jù)時(shí)再使用對(duì)應(yīng)的格式去解析,從而獲取到請(qǐng)求數(shù)據(jù)。
前面提到,Dubbo默認(rèn)使用的通信協(xié)議是Dubbo自己的寫(xiě)的,叫做Dubbo協(xié)議。
除了Dubbo協(xié)議之外,Dubbo還支持以下幾種通信協(xié)議:
- Rest
- gRPC
- Triple
- ...
Rest,就是我們說(shuō)的Http協(xié)議。
當(dāng)使用這種協(xié)議的時(shí)候,Dubbo在啟動(dòng)的時(shí)候會(huì)去創(chuàng)建一個(gè)Http的服務(wù)。
默認(rèn)使用的是Jetty,當(dāng)然也支持切換成Tomcat。
gRPC,谷歌開(kāi)源的高性能RPC框架。
當(dāng)然使用gRPC的時(shí)候,服務(wù)提供者會(huì)啟動(dòng)一個(gè)gRPC的服務(wù)端。
這里你可能有疑問(wèn),Dubbo是RPC框架,gRPC也是RPC框架,為什么要集成gRPC。
其實(shí)這是因?yàn)镈ubbo和gRPC定位不同。
Dubbo其實(shí)不僅僅是一個(gè)RPC框架,它其實(shí)是一套微服務(wù)解決方案,會(huì)承擔(dān)更多的服務(wù)治理相關(guān)的邏輯。
而gRPC的定位是通信協(xié)議與實(shí)現(xiàn),是一款純粹的RPC框架。
Triple協(xié)議就比較厲害了,它是Dubbo在3.x時(shí)發(fā)布的通信協(xié)議。
Triple完全兼容gRPC協(xié)議,可同時(shí)運(yùn)行在HTTP/1和HTTP/2傳輸協(xié)議之上,讓你可以直接使用curl、瀏覽器訪問(wèn)后端Dubbo服務(wù)。
如果要想使用上面的這些協(xié)議,代碼可能需要進(jìn)行一些改動(dòng),這里就不演示了。
序列化協(xié)議
上一節(jié)提到,數(shù)據(jù)在發(fā)送的時(shí)候需要根據(jù)通信協(xié)議按照要求去組裝數(shù)據(jù)。
但是我們都知道,數(shù)據(jù)在網(wǎng)絡(luò)中傳輸使用的是二進(jìn)制。
所以在實(shí)際開(kāi)發(fā)中,要想發(fā)送數(shù)據(jù),一般都是先將需要傳輸?shù)臄?shù)據(jù)轉(zhuǎn)換成字節(jié)序列(數(shù)組),之后再交由操作系統(tǒng)轉(zhuǎn)換成二進(jìn)制進(jìn)行傳輸。
于是就有了一個(gè)問(wèn)題,比如我們想傳輸一個(gè)對(duì)象的數(shù)據(jù),那么我們應(yīng)該按照什么樣的格式將對(duì)象的數(shù)據(jù)轉(zhuǎn)換成字節(jié)序列呢?
而這個(gè)按照什么樣的格式就被稱為序列化協(xié)議。
整個(gè)轉(zhuǎn)換過(guò)程就被稱為序列化,也可以被稱為編碼。
圖片
既然有序列化,那么就有反序列化。
所謂反序列化就是根據(jù)序列化協(xié)議將字節(jié)序列轉(zhuǎn)換成數(shù)據(jù),也被稱為解碼。
當(dāng)通信協(xié)議使用Dubbo協(xié)議時(shí),Dubbo支持以下幾種序列化協(xié)議:
- Java原生
- Hessian2
- Fastjson2
- ...
Dubbo在3.2.0版本之前默認(rèn)使用的Hessian2協(xié)議,3.2.0之后默認(rèn)使用Fastjson2作為序列化協(xié)議。
到這里其實(shí)就算講完了消費(fèi)者整個(gè)調(diào)用的過(guò)程了。
因?yàn)楫?dāng)序列化完成之后,接下來(lái)就只需要將字節(jié)序列通過(guò)網(wǎng)絡(luò)發(fā)送出去即可。
服務(wù)提供者處理請(qǐng)求
當(dāng)服務(wù)提供者監(jiān)聽(tīng)到有請(qǐng)求時(shí),會(huì)獲取到請(qǐng)求的字節(jié)序列。
然后根據(jù)通信協(xié)議,序列化協(xié)議反序列化出傳輸?shù)臄?shù)據(jù)。
從而獲取到消費(fèi)者需要調(diào)用的、接口、方法以及入?yún)⒌葦?shù)據(jù)。
之后就可以找到調(diào)用接口對(duì)應(yīng)的實(shí)現(xiàn),通過(guò)反射進(jìn)行調(diào)用,獲取結(jié)果。
然后再將結(jié)果序列化成字節(jié)數(shù)組,返回給消費(fèi)者。
這樣服務(wù)提供者就處理完成了一次請(qǐng)求。
不過(guò)這里面有一個(gè)小細(xì)節(jié),那就是在調(diào)用接口的實(shí)現(xiàn)之前,也會(huì)經(jīng)過(guò)Filter過(guò)濾。
所以Filter過(guò)濾其實(shí)在提供者和消費(fèi)者兩者都有。
圖片
但是需要注意的是,兩邊的Filter不一定相同,具體取決于這個(gè)Filter是作用在消費(fèi)者端還是提供者端,可通過(guò)如下方式配置
圖片
總結(jié)
到這終于講完了一次RPC請(qǐng)求在Dubbo中經(jīng)歷整個(gè)核心流程。
不知道你看完有什么感受。
這里我再來(lái)畫(huà)一張圖總結(jié)整個(gè)調(diào)用過(guò)程。
圖片
值得注意是,上面提到的所有調(diào)用環(huán)節(jié),注意說(shuō)的是所有,Dubbo都留了對(duì)應(yīng)的擴(kuò)展點(diǎn)。
也就是說(shuō),小到一個(gè)Filter,大到整個(gè)通信協(xié)議你都可以進(jìn)行自定義擴(kuò)展。
從這也可以看出,Dubbo在設(shè)計(jì)上的優(yōu)秀之處。