提升不止一點點廊宪,Dubbo 3.0 預(yù)覽版詳細(xì)解讀,還愣著干啥啊女轿?進來啊

Dubbo 自 2011 年 10 月 27 日開源后箭启,已被許多非阿里系的公司使用,其中既有當(dāng)當(dāng)網(wǎng)蛉迹、網(wǎng)易考拉等互聯(lián)網(wǎng)公司傅寡,也不乏中國人壽、青島海爾等大型傳統(tǒng)企業(yè)婿禽。

自去年 12 月開始赏僧,Dubbo 3.0 便已正式進入開發(fā)階段,并備受社區(qū)和廣大 Dubbo 用戶的關(guān)注扭倾,本文將為您詳細(xì)解讀3.0 預(yù)覽版的新特性和新功能淀零。

下面先解答一下兩個有意思的與 Dubbo 相關(guān)的疑問。

? ? ? ? ·? ? ?為什么 Dubbo 一開源就是 2.0 版本膛壹?之前是否存在 1.0 版本驾中?

? ? ? ? ? ? ??筆者曾做過 Dubbo 協(xié)議的適配兼容唉堪,Dubbo 確實存在過 1.x 版本,而且從協(xié)議設(shè)計和模型設(shè)計上都與 2.0 的開源版本協(xié)議是完全不一樣的肩民。下圖是關(guān)于 Dubbo 的發(fā)展路徑:

? ? ? ? ·? ? ?阿里內(nèi)部正在使用 Dubbo 開源版本嗎唠亚?

是的,非常確定持痰,當(dāng)前開源版本的 Dubbo 在阿里巴巴被廣泛使用灶搜,而阿里的電商核心部門是用的 HSF2.2 版本,這個版本是兼容了 Dubbo 使用方式和 Remoting 協(xié)議工窍。當(dāng)然割卖,我們現(xiàn)在正在做 HSF2.2 的升級,直接依賴開源版本的 Dubbo 來做內(nèi)核的統(tǒng)一患雏。所以鹏溯,Dubbo 是得到大規(guī)模線上系統(tǒng)驗證的分布式服務(wù)框架,這一點毋容置疑淹仑。

Dubbo 3.0 預(yù)覽版的要點

Dubbo 3.0 在設(shè)計和功能上的新增支持和改進丙挽,主要是以下四方面:

? ? ? ? ·? ? ?Dubbo 內(nèi)核之 Filter 鏈的異步化

這里要指出的是,3.0 中規(guī)劃的異步去阻塞和 2.7 中提供的異步是兩個層面的特性匀借。2.7 中的異步是建立在傳統(tǒng) RPC 中 request – response 會話模型上的入客,而 3.0 中的異步將會從通訊協(xié)議層面由下向上構(gòu)建扇雕,關(guān)注的是跨進程循帐、全鏈路的異步問題给赞。通過底層協(xié)議開始支持 streaming 方式,不單單可以支持多種會話模型蓬坡,還可以在協(xié)議層面開始支持反壓、限流等特性磅叛,使得整個分布式體系更具有彈性屑咳。綜上所述,2.7 關(guān)注的異步更局限在點對點的異步(一個 consumer 調(diào)用一個 provider)弊琴,3.0 關(guān)注的異步化兆龙,寬度上則關(guān)注整個調(diào)用鏈上的異步,高度上則向上又可以包裝成 Rx 的編程模型敲董。有趣的是紫皇,Spring 5.0 發(fā)布了對 Flux 的支持,隨后開始解決跨進程的異步問題腋寨。

? ? ? ? ·? ? ?功能方面是 reactive(響應(yīng)式)支持

最近幾年聪铺,?reactive programming這個詞語的熱度迅速提升,Wikipedia 上的 reactive programming 解釋是 reactive programming is a programming paradigm oriented around data flows and the propagation of change. Dubbo3.0會實現(xiàn)Reactive Stream 的 rx 接口萄窜,從而能讓用戶享受到RP帶來的響應(yīng)性提升铃剔,甚至面向 RP 的架構(gòu)升級撒桨。當(dāng)然,我們希望 reactive 不單單能夠帶來事件(event)驅(qū)動的應(yīng)用集成方式的升級键兜,也希望在 Load Balance(選擇最優(yōu)的服務(wù)節(jié)點)凤类,fault tolerance(限流降級時最好做到自適應(yīng))等方面發(fā)揮其積極價值。

? ? ? ? ·? ? ?云原生/ ServiceMesh 方向的探索

我們定下的策略是進入 Envoy 社區(qū)來實現(xiàn) Dubbo 融入 mesh 的理念思想普气,目前 Dubbo 協(xié)議已經(jīng)被 Envoy 支持谜疤。當(dāng)然,Dubbo Mesh 離真正可用還有很長一段距離现诀,其在選址夷磕、負(fù)載均衡和服務(wù)治理方面的工作需要繼續(xù)在數(shù)據(jù)面建設(shè),另外赶盔,控制面板的建設(shè)在社區(qū)也沒有提上日程企锌。

? ? ? ? ·? ? ?融合并支持阿里內(nèi)部

Dubbo 3.0 定下了內(nèi)外融合的策略,也就是說 3.0 的核心最終會在阿里巴巴的生產(chǎn)系統(tǒng)中部署于未,相信通過大流量撕攒、大規(guī)模的考驗,Dubbo 用戶可以獲得一個性能烘浦、穩(wěn)定抖坪、服務(wù)治理實踐各方面俱佳的核心,用戶在生產(chǎn)系統(tǒng)中采用 3.0 也會更加放心闷叉。這一點也是 Dubbo 3.0 最重要的使命擦俐。

Filter 鏈的異步化設(shè)計

Dubbo 最強大的一處設(shè)計是其在 Filter 鏈上的抽象設(shè)計,通過其擴展機制的開放性支持握侧,用戶可以對 Dubbo 做功能增強蚯瞧,并允許各個擴展點被定制來是否保留。

Dubbo?的?Filter?定義如下:

按照“調(diào)用一個遠程服務(wù)的方法就像調(diào)用本地的方法一樣”這種說法品擎,這個直接返回 Result 響應(yīng)的方式是非常好的埋合,用起來是簡單直接,問題是時代變換到了需要關(guān)注體驗萄传,需要走 Reactive 響應(yīng)式的時代甚颂,也回到基本點:invoke一個 invocation 需要經(jīng)過網(wǎng)絡(luò)在不同的進程處理,天然就是異步的過程秀菱,也就是發(fā)送請求(invocation)與接收響應(yīng)(Result)本身是兩個不同的事件振诬,是需要兩個過程方法來在 Filter 鏈處理。那么如何改造這個關(guān)鍵的 SPI 呢衍菱?有兩種方案:

第一種赶么,把 invoke 的返回值改成 CompletableFuture, 好處是一目了然梦碗,Result 不在建議同步獲取了禽绪;但基礎(chǔ)接口的簽名一改會導(dǎo)致代碼改造量巨大蓖救,同時也會讓原有的 SPI 擴展不在支持。

第二種印屁,Result 接口直接繼承 CompletationStage循捺,是代表了響應(yīng)的異步計算。這樣能進避免第一種的劣勢雄人。所以从橘,3.0.0 Preview 版本對內(nèi)部調(diào)用鏈路實現(xiàn)做了一次重構(gòu):基于 CompletableFuture 實現(xiàn)了框架內(nèi)部的全異步調(diào)用,而在外圍編程上础钠,同時支持同步恰力、異步調(diào)用模式。

值得注意的是旗吁,此次重構(gòu)僅限于框架內(nèi)部實現(xiàn)踩萎,對使用方?jīng)]有任何影響即接口上保持完全兼容。此次重構(gòu)的要點有:

? ? ? ? ·? ? ?框架內(nèi)部采用全異步調(diào)用模型很钓,僅在外圍做同步香府、異步適配;

? ? ? ? ·? ? ?內(nèi)置Filter鏈支持異步回調(diào)码倦;

基本工作流程

首先我們來看一個通用的跨網(wǎng)絡(luò)異步調(diào)用的線程模型:

通信框架異步發(fā)送請求消息企孩,請求消息發(fā)送成功后,返回代表業(yè)務(wù)結(jié)果的 CompletableFuture 給業(yè)務(wù)線程袁稽。之后對于 Future 的處理勿璃,根據(jù)調(diào)用類型會有所區(qū)別:

? ? ? ? 1·? ? ?對于同步請求(如上圖體現(xiàn)的場景),業(yè)務(wù)線程會調(diào)用 future.get 同步阻塞等待結(jié)果推汽,當(dāng)收到網(wǎng)絡(luò)層返回的業(yè)務(wù)結(jié)果后补疑,future.get 返回并最終將結(jié)果傳遞給調(diào)用發(fā)起方。

? ? ? ? 2·? ? ?對于異步請求歹撒,業(yè)務(wù)線程不會調(diào)用 future.get癣丧,而是將 future 保存在調(diào)用上下文或者直接返回給調(diào)用者,同時會為 future 注冊回調(diào)監(jiān)聽器栈妆,以便當(dāng)真正的業(yè)務(wù)結(jié)果從通信層返回時監(jiān)聽器可以對結(jié)果做進一步的處理。

接下來具體看一下一次異步 Dubbo RPC 請求的調(diào)用流程:

? ? ? ? 1·? ? ?消費方面向 Proxy 代理編程厢钧,發(fā)出調(diào)用請求鳞尔,請求經(jīng)過 Filter 鏈向下傳遞。

? ? ? ? 2·? ? ?Invoker.invoke() 將請求異步轉(zhuǎn)發(fā)給網(wǎng)絡(luò)層早直,并收到代表返回結(jié)果的 Future寥假。

? ? ? ? 3·? ? ?Future 被包裝到 Result,轉(zhuǎn)而由 Result 代表這次遠程調(diào)用的結(jié)果(由于 Result 的異步屬性霞扬,此時它可能并不包含真正的返回值)糕韧。

? ? ? ? 4·? ? ?Result 繼續(xù)沿著調(diào)用鏈返回枫振,在經(jīng)過每個 Filter 時,F(xiàn)ilter 可選擇注冊 Listener 監(jiān)聽器萤彩,以便在業(yè)務(wù)結(jié)果返回時執(zhí)行結(jié)果預(yù)處理粪滤。

? ? ? ? 5·? ? ?最終 Proxy 調(diào)用 result.recreate() 將結(jié)果返回給消費者:

? ? ? ? ·? ? ?如果方法是 CompletableFuture 簽名,則返回 Future雀扶;

? ? ? ? ·? ? ?如果方法是普通同步簽名杖小,則返回對象默認(rèn)值,F(xiàn)uture 可通過 RpcContext 拿到愚墓;

? ? ? ? 6·? ??調(diào)用方在拿到代表異步業(yè)務(wù)結(jié)果的 Future 后予权,可選擇注冊回調(diào)監(jiān)聽器,以監(jiān)聽真正的業(yè)務(wù)結(jié)果返回浪册。

同步調(diào)用和異步調(diào)用基本上是一致的扫腺,并且也是走的回調(diào)模式,只是在鏈路返回之前做了一次阻塞 get 調(diào)用村象,以確保在收到實際結(jié)果時再返回笆环。Filter 在注冊 Listener 時由于 Future 已處于 complete 狀態(tài),因此會同時觸發(fā)回調(diào) onResponse()/onError()煞肾。

關(guān)于流程圖中提到的 Result咧织,Result 在 Dubbo 的一次 RPC 調(diào)用中代表返回結(jié)果,在 3.0 中 Result 自身增加了代表狀態(tài)的接口籍救,類似 Future 現(xiàn)在 Result 可以代表一次未完成的調(diào)用习绢。

要讓 Result 具備代表異步返回結(jié)果的能力,有兩中方式來實現(xiàn):

1. Result is a Future蝙昙,在 Java 8 中更合理的方式是繼承 CompletionStage 接口闪萄。

2. 讓 Result 實例持有 Future 實例,與 1 的區(qū)別即是設(shè)計中選用“繼承”還是“組合”奇颠。

同時败去,為了讓 Result 更直觀的體現(xiàn)其異步結(jié)果的特性,也為了方便面向 Result 接口編程烈拒,我們可以考慮為Result增加一些異步接口:

Filter SPI

Filter 是 Dubbo 預(yù)置的攔截器擴展 SPI圆裕,用來做請求的預(yù)處理、結(jié)果的后處理荆几,框架本身內(nèi)置了一些攔截器實現(xiàn)吓妆,而從用戶層面,我相信這個 SPI 也應(yīng)該是被擴展最多的一個吨铸。在 3.0 版本中行拢,F(xiàn)ilter 回歸單一職責(zé)的設(shè)計模式,將回調(diào)接口單獨提取到 Listener 中诞吱。

以上是 Filter 的 SPI 定義舟奠,F(xiàn)ilter 的核心定義中只有一個 invoke() 方法用來傳遞調(diào)用請求竭缝。

同時,增加了一個新的回調(diào)接口 Listener沼瘫,每個 Filter 實現(xiàn)可以定義自己的 Listenr 回調(diào)器抬纸,從而實現(xiàn)對返回結(jié)果的異步監(jiān)聽,參考以下是為 MonitorFilter 增加的 Listener 回調(diào)實現(xiàn):

泛化調(diào)用異步接口支持

為了更直觀的做異步調(diào)用晕鹊,泛化接口新增了?

CompletableFuture<Object>$invokeAsync(Stringmethod,String[]parameterTypes,Object[]args)

接口:

這樣松却,當(dāng)我們想做異步調(diào)用時,就可以直接這樣使用:

CompletableFuture<Object> genericService.$invokeAsync(method, parameterTypes, args);

異步與性能

組要注意的是溅话,框架內(nèi)部的異步實現(xiàn)本身并不能提高單次調(diào)用的性能晓锻,相反,由于線程切換和回調(diào)邏輯的存在飞几,異步反而可能會導(dǎo)致單次調(diào)用性能的下降砚哆,但是異步帶來的優(yōu)勢是能減少對資源的占用,提升整個系統(tǒng)的并發(fā)程度和吞吐量屑墨,這點對于 RPC 這種需要處理網(wǎng)絡(luò)延遲的場景非常適用躁锁。更多關(guān)于異步化設(shè)計的好處,請參考其他異步化原理介紹相關(guān)文章卵史。

響應(yīng)式編程支持

響應(yīng)式編程讓開發(fā)者更方便地編寫高性能的異步代碼战转,很可惜,在之前很長一段時間里以躯,dubbo 并不支持響應(yīng)式編程槐秧,簡單來說,dubbo 不支持在 rpc 調(diào)用時使用 Mono/Flux 這種流對象(reative-stream 里流的概念)忧设,給用戶使用帶來了不便刁标。

RSocket 是一個開源的支持 reactive-stream 語義的網(wǎng)絡(luò)通信協(xié)議,他將 reative 語義的復(fù)雜邏輯封裝起來了址晕,使得上層可以方便實現(xiàn)網(wǎng)絡(luò)程序膀懈。

dubbo 在 3.0.0-SNAPSHOT ?版本里基于 RSocket 對響應(yīng)式編程進行了簡單的支持,用戶可以在請求參數(shù)和返回值里使用 Mono 和 Flux 類型的對象谨垃。下面我們給出使用范例启搂,

首先定義接口如下:

然后實現(xiàn)該 demo 接口:

然后配置并啟動服務(wù)端,注意協(xié)議名字填寫 rsocket:

然后配置并啟動消費者消費者如下, 注意協(xié)議名填寫 rsocket:

可以看到配置上除了協(xié)議名使用 rsocket 以外其他并沒有特殊之處刘陶。

實現(xiàn)原理

以前用戶并不能在參數(shù)或者返回值里使用 Mono/Flux 這種流對象(reative-stream 里的流的概念)狐血。因為流對象自帶異步屬性,當(dāng)業(yè)務(wù)把流對象作為參數(shù)或者返回值傳遞給框架之后易核,框架并不能將流對象正確的進行序列化。

dubbo 基于 RSocket 實現(xiàn)了 reative 支持浪默。RSocket 將 reative 語義的復(fù)雜邏輯封裝起來了牡直,給上層提供了簡潔的抽象如下:

我們只需要在此基礎(chǔ)上添加我們的 rpc 邏輯即可缀匕。

? ? ? ?從客戶端視角看,框架建立連接之后碰逸,只需要將請求信息編碼到 Payload 里乡小,然后通過 requestStream 方法即可向服務(wù)端發(fā)起請求。

? ? ? ?從服務(wù)端視角看饵史,rsocket 收到請求之后满钟,會調(diào)用我們實現(xiàn)的 requestStream 方法,我們從 Payload 里解碼得到請求信息之后胳喷,調(diào)用業(yè)務(wù)? ??方法湃番,然后拿到 Flux 類型的返回值即可。

? ? ? ?需要注意的是業(yè)務(wù)返回值一般是 Flux吭露,而 RSocket 要求的是 Flux吠撮,所以我們需要通過 map operator 攔截業(yè)務(wù)數(shù)據(jù),將 BizDO 編碼為 Payload 才可以遞交給我 RSocket讲竿。而 RSocket 會負(fù)責(zé)數(shù)據(jù)的傳輸和 reative 語義的實現(xiàn)泥兰。

經(jīng)過上面的分析,我們知道了 Dubbo 如何基于 RSocket 實現(xiàn)了響應(yīng)式編程的支持题禀。有了響應(yīng)式編程支持鞋诗,業(yè)務(wù)可以更加方便的實現(xiàn)異步邏輯。

小結(jié)

當(dāng)前 Dubbo 3.0 將提供具備當(dāng)代特性(如響應(yīng)性編程)的相關(guān)支持迈嘹,同時汲取阿里內(nèi)部 HSF 的設(shè)計長處來實現(xiàn)兩者的融合削彬,當(dāng)前預(yù)覽版的很多地方還在探討中,希望大家能夠積極反饋江锨,我們都會虛心學(xué)習(xí)并參考吃警。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市啄育,隨后出現(xiàn)的幾起案子酌心,更是在濱河造成了極大的恐慌,老刑警劉巖挑豌,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件安券,死亡現(xiàn)場離奇詭異,居然都是意外死亡氓英,警方通過查閱死者的電腦和手機侯勉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铝阐,“玉大人址貌,你說我怎么就攤上這事。” “怎么了练对?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵遍蟋,是天一觀的道長。 經(jīng)常有香客問我螟凭,道長虚青,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任螺男,我火速辦了婚禮棒厘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘下隧。我一直安慰自己奢人,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布汪拥。 她就那樣靜靜地躺著达传,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迫筑。 梳的紋絲不亂的頭發(fā)上宪赶,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機與錄音脯燃,去河邊找鬼搂妻。 笑死,一個胖子當(dāng)著我的面吹牛辕棚,可吹牛的內(nèi)容都是我干的欲主。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼逝嚎,長吁一口氣:“原來是場噩夢啊……” “哼扁瓢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起补君,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤引几,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后挽铁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伟桅,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年叽掘,在試婚紗的時候發(fā)現(xiàn)自己被綠了楣铁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡更扁,死狀恐怖盖腕,靈堂內(nèi)的尸體忽然破棺而出赫冬,到底是詐尸還是另有隱情,我是刑警寧澤赊堪,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布面殖,位于F島的核電站,受9級特大地震影響哭廉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜相叁,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一遵绰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧增淹,春花似錦椿访、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拳喻,卻和暖如春哭当,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冗澈。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工钦勘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人亚亲。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓彻采,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捌归。 傳聞我的和親對象是個殘疾皇子肛响,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容