自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我發(fā)現(xiàn)一個關于Dubbo服務調用的Bug

開發(fā) 架構
我在使用Dubbo的過程中遇到了如下錯誤:No provider available for the service,本以為這個是服務提供者不存在,但經過我的排查,別的客戶端是能夠正確使用該服務的,原來背后蘊含Dubbo一個BUG。

理論知識

結合我對Dubbo的理解,通常dubbo調用出現(xiàn) No provider available for the service xxx,其原因通常如下:

1.服務方未啟動。

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

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

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

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

背景

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

我覺得很奇怪,服務明明是啟動的,也沒有動態(tài)配置,為什么服務竟然會很奇怪的找不到呢?然后debug下看了代碼,發(fā)現(xiàn)是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.

原來是參數(shù)T009的內部類KeyValuePair未實現(xiàn)序列化導致,但是如果是未實現(xiàn)序列化,應該報錯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é)點數(shù)少于重試的次數(shù)+1(即3次),則沒有匹配的服務節(jié)點,因此在com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker#checkInvokers操作內,會報錯No provider available for the service xxx.

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

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

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

同時修改方法doInvoke如下:

責任編輯:武曉燕 來源: 中間件興趣圈
相關推薦

2025-02-13 07:00:00

Dubbo-goJava服務端

2017-10-10 15:14:23

BUGiOS 11蘋果

2022-11-30 09:18:51

JavaMyBatisMQ

2021-04-22 07:47:47

JavaJDKMYSQL

2022-05-16 08:42:26

Pandasbug

2021-04-28 14:31:35

Dubbo接口日志

2018-01-29 21:56:28

Bug程序程序員

2009-08-18 11:01:51

2021-09-13 08:41:52

職場互聯(lián)網自閉

2022-06-08 08:14:27

Dubbo數(shù)據包源代碼

2016-12-14 10:00:44

數(shù)據結構編譯器

2022-07-01 08:14:28

Dubbo異步代碼

2021-04-30 07:09:48

SQLP0事故

2021-09-03 08:50:50

Dubbo服務引用

2024-05-20 08:25:55

2022-11-10 09:28:40

框架開發(fā)

2019-01-11 09:41:56

網易考拉服務架構微服務

2009-09-14 17:08:02

WebFormView

2020-05-18 08:42:23

CSS背景圖像前端開發(fā)

2013-07-29 09:53:57

醫(yī)療馬云阿里
點贊
收藏

51CTO技術棧公眾號