dubbo剖析:七 網(wǎng)絡(luò)通信總結(jié)

注:文章中使用的dubbo源碼版本為2.5.4

零、文章目錄

  • Dubbo的網(wǎng)絡(luò)分層抽象
  • Dubbo如何保證Client端與Server端的連通性
  • Dubbo編解碼協(xié)議--解決TCP粘包拆包問(wèn)題
  • Dubbo的請(qǐng)求響應(yīng)模式,如何將異步IO變?yōu)橥絉PC
  • Dubbo線程模型總結(jié)

一、Dubbo的網(wǎng)絡(luò)分層抽象

Dubbo整體設(shè)計(jì)

上圖為Dubbo整體設(shè)計(jì)的分層抽象。

網(wǎng)絡(luò)通信位于Remoting模塊:

  • Remoting 實(shí)現(xiàn)是 Dubbo 協(xié)議的實(shí)現(xiàn),如果你選擇 RMI 協(xié)議,整個(gè) Remoting 都不會(huì)用上;
  • Remoting 內(nèi)部再劃為 Transport 傳輸層Exchange 信息交換層;
  • Transport 層只負(fù)責(zé)單向消息傳輸,是對(duì) Mina, Netty, Grizzly 的抽象,它也可以擴(kuò)展 UDP 傳輸;
  • Exchange 層是在傳輸層之上封裝了 Request-Response 語(yǔ)義;


    Remoting模塊類關(guān)系圖

Transport網(wǎng)絡(luò)傳輸層:

  • 抽象 mina 和 netty 為統(tǒng)一接口,以 Message 為中心,擴(kuò)展接口為 Channel, Transporter, Client, Server, Codec;
  • Channel 為網(wǎng)絡(luò)層通道的抽象,其具備單向消息傳輸?shù)哪芰Γ铱梢越壎ê瞳@取屬性;
  • Codec 為編解碼協(xié)議的抽象,其定義了encode()decode()方法,做網(wǎng)絡(luò)byte流和通信消息體的轉(zhuǎn)換;
  • Client 為網(wǎng)絡(luò)層客戶端的抽象,其繼承了Channel接口,同時(shí)定義了重連方法reconnect;
  • Server 為網(wǎng)絡(luò)層服務(wù)端的抽象,其具備單向消息傳輸消息的能力,且可以獲取綁定在其上的所有網(wǎng)絡(luò)通道Channel;
  • Transporter 為網(wǎng)絡(luò)傳輸層入口,提供了創(chuàng)建ServerClient的兩個(gè)核心接口;

Exchange信息交換層:

  • 封裝請(qǐng)求響應(yīng)模式,同步轉(zhuǎn)異步。以 Request, Response 為中心,擴(kuò)展接口為 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
  • Request,Response 為請(qǐng)求響應(yīng)模式消息體的封裝,RPC請(qǐng)求響應(yīng)信息的承載者;
  • ExchangeChannel 為信息交換層通道的抽象,其繼承了Channel接口,并添加了具有同步請(qǐng)求響應(yīng)語(yǔ)義的request()方法;
  • ExchangeClient 為信息交換層客戶端的抽象,繼承了ExchangeChannel接口,具有了發(fā)送同步RPC請(qǐng)求并處理響應(yīng)的能力;
  • ExchangeServer 為信息交換層服務(wù)端的抽象;
  • Exchanger 為信息交換層入口,提供了創(chuàng)建ExchangeServerExchangeClient兩個(gè)核心接口;

二、Dubbo如何保證Client端與Server端的連通性

Dubbo采用雙向心跳的方式檢測(cè)Client端與Server端的連通性。

2.1 心跳請(qǐng)求的發(fā)送

在信息交換層服務(wù)端實(shí)現(xiàn)類HeaderExchangeServer和客戶端實(shí)現(xiàn)類HeaderExchangeClient中包含一個(gè) 心跳定時(shí)任務(wù)HeartBeatTask

  • HeaderExchangeServerHeaderExchangeClient啟動(dòng)時(shí)會(huì)創(chuàng)建一個(gè)定時(shí)線程池執(zhí)行心跳定時(shí)任務(wù),關(guān)閉時(shí)會(huì)同時(shí)關(guān)閉該心跳定時(shí)任務(wù);
  • HeartBeatTask會(huì)循環(huán)檢測(cè)ClientServer中綁定的網(wǎng)絡(luò)通道Channel,將通道中 最近一次接收或發(fā)送消息 的時(shí)間與當(dāng)前時(shí)刻做比較,如果兩者相隔超過(guò)了一個(gè) 心跳周期 ,則主動(dòng)構(gòu)建并通過(guò)Channel 向?qū)Χ税l(fā)送一個(gè) 心跳請(qǐng)求消息

2.2 心跳請(qǐng)求的接收及處理

在請(qǐng)求接收的Handler處理鏈路中,包含有一個(gè) 心跳消息處理器HeartbeatHandler

  • 對(duì)于所有類型的請(qǐng)求消息,該處理器都會(huì)更新對(duì)應(yīng)通道中 最近一次接收消息 的時(shí)間;
  • 對(duì)于心跳請(qǐng)求消息,該處理器接收心跳請(qǐng)求并構(gòu)建對(duì)應(yīng)的心跳響應(yīng)通過(guò)通道Channel發(fā)送回去;

2.3 心跳超時(shí)的檢測(cè)及處理

在信息交換層服務(wù)端實(shí)現(xiàn)類HeaderExchangeServer和客戶端實(shí)現(xiàn)類HeaderExchangeClient中包含一個(gè) 心跳定時(shí)任務(wù)HeartBeatTask

  • HeartBeatTask會(huì)循環(huán)檢測(cè)ClientServer中綁定的網(wǎng)絡(luò)通道Channel,當(dāng)發(fā)現(xiàn)通道中 最近一次接收消息 的時(shí)間與當(dāng)前檢測(cè)時(shí)間間隔超過(guò) 心跳超時(shí)時(shí)間 時(shí),會(huì)觸發(fā)心跳超時(shí)邏輯的執(zhí)行;
  • 對(duì)于服務(wù)端,心跳超時(shí)發(fā)生時(shí),會(huì)調(diào)用channel.close()主動(dòng)斷連對(duì)應(yīng)通道;
  • 對(duì)于客戶端,心跳超時(shí)發(fā)生時(shí),會(huì)調(diào)用client.reconnect()執(zhí)行網(wǎng)絡(luò)通道重連邏輯。如果重連失敗則不做處理等待下次心跳超時(shí)檢測(cè)時(shí)再次觸發(fā)重連邏輯

三、Dubbo編解碼協(xié)議,解決TCP粘包拆包問(wèn)題

Dubbo協(xié)議頭
  • Dubbo在TCP協(xié)議的基礎(chǔ)上添加了自己的消息協(xié)議頭,以進(jìn)行Request、Response消息的編解碼,解決TCP的粘包拆包問(wèn)題。
  • 粘包拆包問(wèn)題的說(shuō)明請(qǐng)見 netty學(xué)習(xí)系列八:拆包器

3.1 請(qǐng)求消息協(xié)議頭說(shuō)明

  • 0-1byte:一個(gè)魔數(shù)數(shù)字MAGIC,就是一個(gè)固定的數(shù)字
  • 2byte:請(qǐng)求的雙向或單向標(biāo)記
  • 3byte:無(wú)
  • 4-11byte:請(qǐng)求ID,long類型。異步變同步的全局唯一ID,用來(lái)做consumer和provider的來(lái)回通信標(biāo)記
  • 12-15byte:消息體長(zhǎng)度,int類型。也就是消息頭+請(qǐng)求數(shù)據(jù)的長(zhǎng)度

3.2 響應(yīng)消息協(xié)議頭說(shuō)明

  • 0-1byte:一個(gè)魔數(shù)數(shù)字MAGIC,就是一個(gè)固定的數(shù)字
  • 2byte:序列化組件類型,它用于和客戶端約定序列化編碼號(hào)
  • 3byte:它是Response的結(jié)果響應(yīng)碼,例如OK=20
  • 4-11byte:請(qǐng)求ID,long類型。異步變同步的全局唯一ID,用來(lái)做consumer和provider的來(lái)回通信標(biāo)記
  • 12-15byte:消息體長(zhǎng)度,int類型。也就是消息頭+請(qǐng)求數(shù)據(jù)的長(zhǎng)度

3.3 粘包拆包的解決

基本原理就是不斷從TCP緩沖區(qū)中讀取數(shù)據(jù),并將新讀取到的數(shù)據(jù)向后追加到 本地消息緩存 中,然后進(jìn)行解碼處理:

  • 如果當(dāng)前本地消息緩存中不足以拼接成一個(gè)業(yè)務(wù)數(shù)據(jù)包,那就保留數(shù)據(jù),繼續(xù)從tcp緩沖區(qū)中讀取數(shù)據(jù);
  • 如果當(dāng)前本地消息緩存中能夠拼接成一個(gè)業(yè)務(wù)數(shù)據(jù)包,那就將對(duì)應(yīng)數(shù)據(jù)解碼成一個(gè)完整的業(yè)務(wù)數(shù)據(jù)包并傳遞給業(yè)務(wù)邏輯處理,本地消息緩存中剩余的多余數(shù)據(jù)仍然保留,以便和下次讀到的數(shù)據(jù)嘗試拼接;
  • TCP協(xié)議保證了TCP數(shù)據(jù)報(bào)的 不丟不重不亂序 ,這是Dubbo編解碼方式的前提;

四、Dubbo的請(qǐng)求響應(yīng)模式,如何將異步IO變?yōu)橥絉PC

3.1 發(fā)起RPC調(diào)用請(qǐng)求的業(yè)務(wù)線程,是如何同步阻塞等待直到RPC響應(yīng)返回的?

  • 業(yè)務(wù)請(qǐng)求線程調(diào)用HeaderExchangeClient.request()方法發(fā)送RPC請(qǐng)求消息到網(wǎng)絡(luò),然后直接調(diào)用DefaultFuture.get()方法阻塞等待RPC執(zhí)行結(jié)果;
  • get()阻塞等待的本質(zhì):循環(huán)檢測(cè)Response結(jié)果是否被設(shè)置成功,如果不成功使用Condition.await()阻塞直到結(jié)果返回;
  • NettyClient接收到RPC響應(yīng)消息時(shí),會(huì)調(diào)用DefaultFuture.received()方法,該方法中觸發(fā)了Condition.signal()通知業(yè)務(wù)請(qǐng)求線程解除阻塞等待狀態(tài);

3.2 對(duì)于全雙工的網(wǎng)絡(luò)通信,在多線程并發(fā)請(qǐng)求響應(yīng)的情況下,如果找到RPC響應(yīng)Response對(duì)應(yīng)的RPC請(qǐng)求Request?

  • 對(duì)于不同的服務(wù)消費(fèi)者客戶端,請(qǐng)求響應(yīng)自然與其網(wǎng)絡(luò)通道Channel綁定,不會(huì)存在消費(fèi)者A接收到消費(fèi)者B的RPC響應(yīng)的情況;
  • 對(duì)于同一服務(wù)消費(fèi)者客戶端,在RPC請(qǐng)求Request構(gòu)建時(shí)生成并攜帶全局唯一自增ID,RPC響應(yīng)Response會(huì)攜帶該ID返回。消費(fèi)者客戶端只需維護(hù) “唯一ID與RPC請(qǐng)求的關(guān)系Map<Long, DefaultFuture> FUTURES”即可定位RPC響應(yīng)對(duì)應(yīng)的RPC調(diào)用上下文;

五、Dubbo線程模型總結(jié)

Dubbo請(qǐng)求響應(yīng)線程模型圖
  • 藍(lán)色代表“發(fā)送RPC請(qǐng)求”過(guò)程,由 業(yè)務(wù)請(qǐng)求線程 執(zhí)行,通過(guò)NettyChannel將請(qǐng)求數(shù)據(jù)放入Netty的IO任務(wù)隊(duì)列后,構(gòu)建ResponseFuture并返回。此時(shí)RPC請(qǐng)求發(fā)送及響應(yīng)接收并未真正完成;
  • 紫色是基于Netty的網(wǎng)絡(luò)消息收發(fā)過(guò)程,通過(guò)當(dāng)前網(wǎng)絡(luò)通道綁定的NioEventLoop線程輪詢完成;
  • 橙色代表“接收RPC響應(yīng)”過(guò)程,該過(guò)程在 Dubbo業(yè)務(wù)線程池 中執(zhí)行,處理RPC響應(yīng)消息并交由ResponseFuture觸發(fā)接收響應(yīng)的邏輯;
  • 綠色代表“獲取RPC調(diào)用結(jié)果”過(guò)程,由 業(yè)務(wù)請(qǐng)求線程 執(zhí)行,阻塞直到從ResponseFuture中獲取到RPC響應(yīng)結(jié)果;
  • 紅色代表“接收并處理RPC請(qǐng)求”過(guò)程,在 Dubbo業(yè)務(wù)線程池 中執(zhí)行。RPC請(qǐng)求消息由HeaderExchangeHandler處理,通過(guò)DubboInvoker反射執(zhí)行 實(shí)際接口實(shí)現(xiàn)類 得到執(zhí)行結(jié)果,并封裝成Response交由網(wǎng)絡(luò)通道發(fā)送RPC響應(yīng)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容