dubbo發送過程編碼失敗,會喚醒發送線程嗎?

dubbo發送過程編碼失敗,會喚醒發送(客戶端業務)線程嗎?如何實現的?

在上篇文章 dubbo坑- No provider available for the service xxx 中,如果dubbo請求階段,編碼異常,而業務線程依然在等待響應,dubbo如何處理的?總不能等待超時,響應個超時異常吧,這不合理,接下來看dubbo編碼異常,如何處理的

回顧下之前自己分析的dubbo transport層記錄,詳細記錄了dubbo調用鏈路(包括netty channelhandler chain,dubbo channelhandler chain)的執行,在簡單回顧下:

客戶端發送:此時是在業務線程執行,客戶端業務線程依次執行 InvokerInvocationHandler入口 -> RegistryDirectory獲取服務集合 -> tagRouter過濾 -> 負載均衡選取一個Invoker -> dubbo consumer filter chain -> DubboInvoker執行調用invoke -> Exchange層封裝請求模型Request且創建DefaultFuture並阻塞等待 -> 網絡客戶端NettyClient發送消息 -> dubbo Channel即NettyChannel發送 -> 調用netty channle發送 io.netty.channel.Channel.writeAndFlush(message),接着觸發執行netty pipeline的outbound事件,執行順序TailContext->NettyClientHandler->InternalEncoder->InternalDecoder->HeadContext,其中在TailContext內由業務線程切換到reactor IO線程,接着InternalEncoder進行編碼,最終由HeadContext把數據發送給服務方;

客戶端接收服務端響應:reactor IO線程監聽到selector有read事件,執行processSelectedKeys(),觸發執行netty pipeline的inbound事件,執行順序【HeadContext->InternalDecoder->InternalEncoder->NettyClientHandler->TailContext】,由InternalDecoder解碼,接着在NettyClientHandler#channelRead執行,NettyClientHandler持有dubbo channelhandler chain,因此鏈式執行dubbo channelhandler chain,即NettyClient->MultiMessageHandler->HeartbeatHandler->AllChannelHandler->DecodeHandler->HeaderExchangeHandler->DubboProtocol$1,這裡重要的是在AllChannelHandler內由IO線程切換到業務線程(封裝響應Response為ChannelEventRunnable,提交到dubbo業務線程池),接着在業務線程上HeaderExchangeHandler判斷mesage是Response,處理響應,喚醒DefaultFuture的阻塞等待。

接着客戶端業務線程被喚醒,根據Response內容處理,獲取返回的數據結果/異常。

以上就是dubbo整個發送-響應的整個流程,重點是netty pipeline和dubbo channelhandler chain,都是責任鏈模式增加功能。

接着分析我們這個問題,從上面回顧的流程可知,未實現序列化,那麼異常肯定發生在dubbo編碼階段,即InternalEncoder拋出異常,異常是java.lang.RuntimeException,異常信息Serialized class com.zzz.ioc.codec.util.KeyValuePair must implement java.io.Serializable Java field: private com.zzz.ioc.codec.util.KeyValuePair com.zzz.ioc.protocol.t808.T0900.message,異常封裝在netty DefaultChannelPromise,因此在NettyClientHandler獲取InternalEncoder.write結果(此過程在IO線程執行),判斷是否有無異常,代碼如下

image-20220327001350572

消息發送有異常,則mock response返回,接着執行NettyClientHandler持有的dubbo channelhandler chain[NettyClient->MultiMessageHandler->HeartbeatHandler->AllChannelHandler->DecodeHandler->HeaderExchangeHandler->DubboProtocol$1],AllChannelHandler執行,IO線程切換到業務線程(dubbo客戶端線程池,線程名稱DubboClientHandler-開頭),接着業務線程上執行HeaderExchangeHandler,處理response,喚醒發送等待線程。此過程為了避免write操作失敗,mock Request,然後和正常接收響應基本一樣的處理方式(不同之處是不經過selector的processSelectedKeys())喚醒發送線程。通信框架出現這個問題也不容易,但是dubbo設計的非常巧妙。

小結:

回答前面提問

1.dubbo發送過程編碼失敗,會喚醒發送線程嗎?

會喚醒發送線程,否則發送線程就是timeout異常,實際並沒有。

如何實現的?

發送異常,比如編碼異常,NettyClientHandler 進行mock response,接着和正常處理響應基本相同方式,觸發NettyClientHandler 持有的dubbo channelhandler chain,由AllChannelHandler封裝響應Response為ChannelEventRunnable,提交到dubbo業務線程池(cache線程池,線程名DubboClientHandler-開頭),線程由IO線程切換到dubbo業務線程執行Exchange,即HeaderExchangeHandler處理response,繼而喚醒發送線程,最後發送(客戶端業務)線程處理響應業務邏輯。