Dubbo——Transport網絡傳輸層

Transport網絡傳輸層


1請求/響應的處理流程


NettyHandler:繼承netty對象SimpleChannelHandler,重寫了channelConnected、channelDisconnected、messageReceived、writeRequested、exceptionCaught方法,當netty的通道發生連接、斷開連接、收到消息、寫入消息、捕獲異常等事件時觸發NettyHandler中的對應方法。在這些方法中後續的處理鏈爲:NettyServer/NettyClient—>MultiMessageHandler-->HeartbeatHandler—> AllChannelHandleràDecodeHandlerà

HeaderExchangerHandleràDubboProtocol$requestHandler,此鏈條爲回調工作的處理流程。

 

MultiMessageHandler 對於消息的received事件,如果消息是批量傳輸的,解碼後會由MultiMessage承載,並遍歷其中的消息,交由下一個handler處理。


HeartbeatHandler:設置通道的讀寫時間戳

1)對於connected事件,設置通道的讀寫時間戳爲當前時間;

2)對於disconnected事件,清空讀寫時間戳;

3)對於sent事件,設置通道的寫時間戳爲當前時間;

4)對於received事件,設置通道的讀時間戳爲當前時間;若消息是心跳消息請求(mEvent=true and mData=null),如果此心跳事件需要響應(mTwoWay=true),則構建心跳響應對象Response,併發送響應消息,不做後續channel處理;若消息是心跳響應(mEvent=true andmData=null),記錄日誌直接返回,不在做後續的channel處理;若不是心跳消息,則交由下一個處理器處理。

 

由Dispatcher創建的各類Handler處理器:根據URL參數dispather選擇Dispatcher類,不同的Dispatcher創建不同的Handler,表示通道的事件(connected、disconnected、received、caught、sent)的處理模式。在這些Handler中構建異步執行任務ChannelEventRunnable,異步執行connected、disconnected、received、caught、sent等操作。目前支持四種Handler處理器:

1)AllChannelHandler:除發送消息之外,所有的事件都採用線程池處理;

2)ExecutionChannelHandler:除發送消息之外,其他全部使用線程池處理;與AllChannelHandler不同之處在於,若創建的線程池ExecutorService不可用,AllChannelHandler將使用共享線程池,而ExecutionChannelHandler只有報錯了。

3)ChannelHandler:所有事件都直接有ChannelHandler處理,不採用線程池;

4)MessageOnlyChannelHandler:只有接受消息採用線程池;

5)ConnectionOrderedDispatcher:沒搞明白;

在上述Handler的初始化過程中,會根據URL的參數threadpool來創建線程池,目前支持的線程池類型有三種,默認選擇FixedThreadPool。

1)FixedThreadPool:此線程池啓動時即創建固定大小的線程數,不做任何伸縮;

2)CachedThreadPool:此線程池可伸縮,線程空閒一分鐘後回收,新請求重新創建線程;

3)LimitedThreadPool:此線程池一直增長,直到上限,增長後不收縮;

 

       DecodeHandler:對讀取的消息進行decode操作。

 

       HeaderExchangeHandler:處理connected、disconnected、sent、received、caught等事件,並調用DubboProtocol$requestHandler內部類響應的事件方法。

1)connected事件:更新通道的讀取時間戳和寫入時間戳。調用DubboProtocol$requestHandler匿名內部類的connected事件方法。

2)disconnected事件:更新通道的讀取時間戳和寫入時間戳。調用DubboProtocol$requestHandler匿名內部類的disconnected事件方法(由ondisconnect屬性配置)。

3)sent事件:更新通道的寫入時間戳。回調DubboProtocol$requestHandler匿名內部類的sent,由於該內部類未重寫sent方法,即調用父類的該方法,父類未實現任何處理邏輯。如果消息是Request,即是發送請求,則根據請求的唯一標識ID獲取DefaultFuture對象,並設置發送時間爲當前時間,用於在超時之後分析客戶端的耗時、服務端的耗時。

4)received事件:更新通道的讀取時間戳。如果是Request請求,並且需要對請求做回執時,則首先調用DubboProtocol$requestHandler匿名內部類的replay方法,在該方法中完成服務端本地方法調用並返回結果;然後根據Request對象的ID構建Response對象,將回調服務的執行結果作爲Response對象的結果字段;最後調用channel.send方法向客戶端發送響應消息。如果是Request請求並且不需要對請求做回執時,則調用DubboProtocol$requestHandler匿名內部類的received方法。 如果是Response且不是心跳響應,則根據response中的ID獲取DefaultFuture對象,若DefaultFuture對象不存在,則該響應已經超時並且已經被刪除了,若還存在,則設置response的值,喚醒線程,DefaultFuture對象的get方法返回調用值。

 

       DubboProtocol$requestHandler:匿名內部類,實現了抽象類ExchangeHandlerAdapter類。

       1)connected方法:檢查URL中是否有“onconnect”參數,若有則回調該參數指定的方法;

       2)disconnected方法:檢查URL中是否有“ondisconnect”參數,若有則回調該參數指定的方法;

       3)received方法:若消息是Invocation對象則調用reply方法,根據生成的serviceKey在AbstractProtocol.exporterMap中查找DubboExporter對象,然後根據此exporter對象獲取服務端創建的invoker對象,從而完成服務端的本地方法調用;若不是則調用父類的received方法,不進行任何邏輯處理。


一、消費端發起遠程調用的底層通信活動圖



二、服務提供端接收請求並響應的底層通信



2 回調服務的處理邏輯

一、服務器的處理方式

       Netty爲例,首先在初始化NettyClient或者NettyServer的時候,根據URL中的codec參數選擇具體的codec類,默認使用DubboCountCodec類。

       如下代碼所示,在啓動Netty客戶端或者服務端的時候在Nettypipeline中添加了編解碼器。該編解碼器就是上面根據URL的參數選擇出來的


decoder爲解碼器,是一個SimpleChannelUpstreamHandler,從Socket到Netty中的時候,需要解碼,也就是接收消息的時候,需要解碼。

encoder是編碼器,是OneToOneEncoder,這個類實現了ChannelDownstreamHandler,從發送消息的時候,需要編碼。

nettyHandler實現了ChannelUpstreamHandler, ChannelDownstreamHandler兩個,上下的時候都需要處理。

接收消息的時候,會先執行decoder,然後執行nettyHandler。

發送消息的時候,會先執行nettyHandler,然後執行encoder。

 

二、客戶端發送調用請求的邏輯

1、先執行nettyHandler的writeRquested方法,從而decodeHandler的sent方法,該handler未實現sent方法,因而調用父類的方法透傳請求。

2、執行encoder,調用鏈爲:NettyCodecAdapter$InternalEncoder.encode --> DubboCountCodec.encode-->DubboCodec.encode-->ExchangeCodec.encode à…à DubboCodec.encodeRequestData,在該調用鏈中,最終調用CallbackServiceCodec.encodeInvocationArgument方法,在該方法中檢查遠程方法的參數是否爲回調函數,若是則將客戶端中調用遠程方法時傳入的回調函數參數暴露出來提供服務端使用,在CallbackServiceCodec.exportOrunexportCallbackService方法中完成回調函數是服務暴露,大致邏輯是:

    1)生產一個唯一實例ID;

    2)代理工廠創建Invoker代理;

       3)調用代理工廠Protocol$Adpative根據URL中的協議選擇具體的Protocol處理類,調用export方法,具體邏輯與《各類型暴露服務邏輯》一致。

      

三、服務端接受客戶端請求的處理邏輯

1、先執行decoder,調用鏈如下:

NettyCodecAdapter$InternalDecoder.messageReceived –>DubboCountCodec.decode --> DubboCodec.decode--> DubboCodec.decodeBody -->DecodeableRpcInvocation.decode -->…-->CallbackServiceCodec.decodeInvocationArgument,在decodeInvocationArgument方法中判斷該調用的方法中參數是否爲回調函數,若是則調用CallbackServiceCodec.referOrdestroyCallbackService方法完成對客戶端暴露的回調函數的服務引用。大致邏輯:

1)初始化ChannelWrappedInvoker 對象,其中將與客戶端建立的通道Channel對象中參數之一,此Channel參數是回調函數消息發送的重要通道,在觸發回調工作時,利用此Channel創建HeaderExchangeClient對象,由該對象完成回調的請求工作,具體邏輯與消費端發起遠程調用的邏輯基本一致。

2)創建服務類的本地代理,即爲ChannelWrappedInvoker 對象創建代理,將此代理作爲服務端方法中回調參數的請求值,從而在服務端的方式實現中就可以使用該代理完成遠程回調工作。

3)將DecodeableRpcInvocation類中的hasDecoded變量設置爲true,以免在DecodeHandler中重複執行此解碼工作。


發佈了59 篇原創文章 · 獲贊 56 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章