Dubbo的几个常见异常及解决方案

总结几个dubbo常见的异常以及解决方法,有通信相关的,也有性能相关的


先来一个最常见的:

com.alibaba.dubbo.rpc.RpcException: No provider available from registry 192.168.116.150:2181 for service slg.rainbow.user.service.UserService on consumer 192.168.116.1 use dubbo version 2.6.2, please check status of providers(disabled, not registered or in blacklist).
at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:575) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:74) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:271) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:232) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:75) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52) ~[dubbo-2.6.2.jar:2.6.2]
……

找不到服务,这时候可能有这么几种情况:

  1. provider服务没启动,或者zookeeper宕机了
  2. 检查@Service是不是用成spring里的注解了,必须使用com.alibaba.dubbo.config.annotation.Service
  3. 检查@Reference注解,是不是写成了jdk里的注解jdk.nashorn.internal.ir.annotations.Reference(表现形态就是dubbo监控中心里面死活不出现这个消费者,consumer中也会报空指针)

在dubbo中有两个与服务连接状态有关的配置项,一个是两端都有的的dubbo.registry.check,表示是否检查注册中心的状态,默认为true,也就是只要zk出现了问题,这个服务就不停报异常(如果是尚未启动的服务将无法启动),即便zk恢复它也无法恢复,如果配置成false,那么它会不停检测zk,只要等到zk正常了服务也就正常了。

另一个是只有consumer端才有的配置项dubbo.consumer.check,默认值也为true,功能与上面的类似,只不过它检测的是consumer所调用的provider服务是否正常,如果配置成false,就算provider没能提供服务,consumer也能正常启动持续工作,直到provider恢复。


下面一个是由于服务IP冲突而导致的 异常:

com.alibaba.dubbo.remoting.RemotingException: client(url: dubbo://172.17.0.16:20881/slg.rainbow.user.service.UserService?anyhost=true&application=user-service&check=false&codec=dubbo&default.actives=10&default.check=false&default.loadbalance=random&default.retries=2&default.timeout=5000&dubbo=2.6.2&generic=false&heartbeat=60000&interface=slg.rainbow.user.service.UserService&methods=doLogin,checkUserExist,saveUser,findUserByToken&pid=15168&register.ip=192.168.116.1&remote.timestamp=1561446974401&revision=0.0.1-SNAPSHOT&side=consumer&timestamp=1561447455429) failed to connect to server /172.17.0.16:20881 client-side timeout 3000ms (elapsed: 3030ms) from netty client 192.168.116.1 using dubbo version 2.6.2
at com.alibaba.dubbo.remoting.transport.netty.NettyClient.doConnect(NettyClient.java:127) [dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.remoting.transport.AbstractClient.connect(AbstractClient.java:275) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.remoting.transport.AbstractClient.(AbstractClient.java:89) ~[dubbo-2.6.2.jar:2.6.2]
……

由于之前我已经在docker环境下启动过UserService这个服务,因此注册中心记录了其172.17.0.16:20881这个IP地址,但是我忘记了,又从本机的程序里启动了一次,而本机的IP是192网段的,因此dubbo报了一个无法连接到172.17.0.16:20881的异常,将docker中已经启动的服务关闭就好了。


接下来是两个与性能有关的异常,在做压测时,后台报出了线程池耗尽的异常:

com.alibaba.dubbo.remoting.RemotingException: Server side(192.168.116.1,20881) threadpool is exhausted ,detail msg:Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-192.168.116.1:20881, Pool Size: 500 (active: 500, core: 500, max: 500, largest: 500), Task: 1374 (completed: 874), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://192.168.116.1:20881!
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.returnFromResponse(DefaultFuture.java:222) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:139) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:112) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:95) ~[dubbo-2.6.2.jar:2.6.2]
……

这种问题有这么几种解决办法:

  1. 调整provider端的dubbo.provider.threads参数的大小,调大一些即可
  2. 调整consumer端的dubbo.consumer.actives参数的大小,调小一些即可
  3. 增加provider服务的数量,分担压力

前两种方法虽然能够解决线程池耗尽的异常,但是却有可能带来另一个异常,那就是超时异常:

com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout. start time: 2019-06-24 19:53:11.837, end time: 2019-06-24 19:53:16.838, client elapsed: 0 ms, server elapsed: 5001 ms, timeout: 5000 ms, request: Request [id=338, version=2.0.0, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=doLogin, parameterTypes=[class java.lang.String, class java.lang.String], arguments=[5042865b26, 863496c025a074da7e43], attachments={path=slg.rainbow.user.service.UserService, interface=slg.rainbow.user.service.UserService, version=0.0.0, timeout=5000}]], channel: /192.168.116.1:61686 -> /192.168.116.1:20881
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:136) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:112) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:95) ~[dubbo-2.6.2.jar:2.6.2]
… 69 common frames omitted

这是因为不管是增加线程数量,还是限制consumer方法调用的并发量,都无法加快provider端每条线程的业务处理能力。因此线程池大到一定程度就无法再提高provider端的处理能力了,同理限制actives数量也只是能减缓从线程池中取线程的速率,在链路外等待的request请求会不断堆积,最后导致超时。所以最终的解决办法还是增加provider数量分担压力。

这里就不得不献上这张dubbo调用模型图,它可以让我们更清晰的了解到dubbo中各个调优参数的作用原理:
在这里插入图片描述
线程池是否够用,以及是否会超时,与外部请求数量以及服务处理能力都有关系,具体调优参数的说明可以参考这篇文章《dubbo参数调优说明》

文章里有一句很重要的话:

从上面的分析,可以看出如果consumer数*actives>provider数*threads且queues=0,则会存在部分请求无法申请到资源,重试也有很大几率失败。 当需要对一个接口的不同方法进行不同的并发控制时使用executes,否则调整threads就可以。

我们可以按照这个原则来平衡actives和threads参数间的关系

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值