日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯網營銷解決方案
我發(fā)現一個關于Dubbo服務調用的Bug

理論知識

1.服務方未啟動。

成都創(chuàng)新互聯公司專注于康巴什企業(yè)網站建設,自適應網站建設,商城網站建設。康巴什網站建設公司,為康巴什等地區(qū)提供建站服務。全流程按需求定制開發(fā),專業(yè)設計,全程項目跟蹤,成都創(chuàng)新互聯公司專業(yè)和態(tài)度為您提供的服務

2.代碼內客戶端和服務端的group、version不匹配。

3.有dubbo tag路由過濾,標簽不匹配。

4.動態(tài)配置過濾,沒有匹配的服務(比如disable等)。

但這次遇到一個非以上問題,因此研究了一番,發(fā)現了dubbo在實現上有一些瑕疵。

背景

在做JT808協(xié)議指令數據上行指令,指令通過808采集平臺(netty長連接),解析后,通過dubbo調用服務,做指令的業(yè)務邏輯處理,奇怪是服務存在,但是卻報錯No provider available for the service com.xxx.ioc.api.service.JTService,錯誤截圖如下:

我覺得很奇怪,服務明明是啟動的,也沒有動態(tài)配置,為什么服務竟然會很奇怪的找不到呢?然后debug下看了代碼,發(fā)現是dubbo編碼階段報錯。

io.netty.handler.codec.EncoderException: java.lang.RuntimeException: Serialized class com.xxx.ioc.codec.util.KeyValuePair must implement java.io.Serializable Java field: private com.xxx.ioc.codec.util.KeyValuePair com.xxx.ioc.protocol.t808.T0900.message.

原來是參數T009的內部類KeyValuePair未實現序列化導致,但是如果是未實現序列化,應該報錯Serialized class xxx must implement java.io.Serializable的錯誤,但是為什么收到的錯誤卻是No provider available for the service xxx,帶著這個問題,分析一波。

分析過程

調用鏈路根據之前自己分析的dubbo transport層記錄,dubbo客戶端調用時序圖如下(可以參考鏈接的泳道圖):

dubbo客戶端的調用的基本流程說明如下:

  • 客戶端經netty pipeline的TailContext處理,業(yè)務線程切換到reactor IO線程,業(yè)務線程在DefaultFuture.get()阻塞等待響應。
  • dubbo的編碼/解碼是在reactor IO線程處理,編碼拋出異常,消息不會發(fā)送給服務方,此時異常(錯誤碼BAD_REQUEST)被被封裝為Response,繼而喚醒業(yè)務線程在DefaultFuture.get()阻塞等待。

這里有個疑問,編碼失敗,那么是如何返回響應消息的呢?后面下篇文章分析),在執(zhí)行com.alibaba.dubbo.remoting.exchange.support.DefaultFuture#returnFromResponse,把異常信息封裝為RemotingException進行拋出,代碼如下:

private Object returnFromResponse() throws RemotingException {
Response res = response;
if (res == null) {
throw new IllegalStateException("response cannot be null");
}
if (res.getStatus() == Response.OK) {
return res.getResult();
}
if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
throw new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage());
}
throw new RemotingException(channel, res.getErrorMessage());//序列化異常(錯誤碼BAD_REQUEST)被封裝為RemotingException向上拋出
}

重點關注一下調用鏈中的異常處理:

  • 在com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvoke內異常被catch,異常信息被封裝為RpcException(異常code=NETWORK_EXCEPTION)向上拋。
  • 接著在com.alibaba.dubbo.rpc.protocol.AbstractInvoker#invoke內異常RpcException被catch,由于異常code=NETWORK_EXCEPTION,非業(yè)務異常代碼,因此異常繼續(xù)向上拋。
  • 最后異常RpcException在com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke內被catch,由于是failover失效轉移策略默認重試2次,因此接著嘗試去調用調用其它節(jié)點,如果服務的節(jié)點數少于重試的次數+1(即3次),則沒有匹配的服務節(jié)點,因此在com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker#checkInvokers操作內,會報錯No provider available for the service xxx.

詳細的代碼調用截圖如下所示:

因此就淹沒了序列化異常,導致真正的異常失真。這也是dubbo錯誤提示的一點小問題,如果要修復,解決方法也簡單:FailoverClusterInvoker新增如下方法:

private void checkInvokers(List> invokers, Invocation invocation, RpcException le) {
if (invokers == null || invokers.isEmpty()) {
if (le != null) {
throw le;
}
checkInvokers(invokers, invocation);//請求父類
}
}

同時修改方法doInvoke如下:


當前題目:我發(fā)現一個關于Dubbo服務調用的Bug
當前地址:http://www.5511xx.com/article/dpsojhj.html