首页 > 代码库 > dubbo超时的深思

dubbo超时的深思

在dubbo的provider和consumer的配置文件中,如果都配置了timeout的超时时间,dubbo默认以consumer中配置的时间为准

provider.xml的配置:

<dubbo:service timeout="4000" retries="0" interface="com.dingding.tms.bms.service.BillingZfbCodOrderService" ref="billingZfbCodOrderService" registry="globalRegistry"/>

conusmer中的配置:

<dubbo:reference id="billingInterService" interface="com.dingding.tms.bms.service.BillingInterService" protocol="dubbo" check="false" registry="globalRegistry" timeout="3000"/>


最后这个service在调用时的超时时间就是3秒

另外,

1,consumer会在超过3秒时得到一个调用超时的异常。

2,provider中代码的执行不会因为超时而中断,在执行完毕后,会得到一个dubbo的警告。

在Provider上尽量多配置Consumer端属性
原因如下:

  1. 作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等

  2. 在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值。否则,Consumer会使用Consumer端的全局设置,这对于Provider不可控的,并且往往是不合理的

  3. PS: 配置的覆盖规则:1) 方法级配置别优于接口级别,即小Scope优先 2) Consumer端配置 优于 Provider配置 优于 全局配置,最后是Dubbo Hard Code的配置值(见配置文档)

比如:
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService"
    timeout="300" retry="2" loadbalance="random" actives="0"/>
 
< dubbo:service interface="com.alibaba.hello.api.WorldService" version="1.0.0" ref="helloService"
    timeout="300" retry="2" loadbalance="random" actives="0" >
    <dubbo:method name="findAllPerson" timeout="10000" retries="9" loadbalance="leastactive" actives="5" />
< dubbo:service/>


在Provider可以配置的Consumer端属性有:

  1. timeout,方法调用超时

  2. retries,失败重试次数,缺省是2(表示加上第一次调用,会调用3次)

  3. loadbalance,负载均衡算法(有多个Provider时,如何挑选Provider调用),缺省是随机(random)。还可以有轮训(roundrobin)、最不活跃优先(leastactive,指从Consumer端并发调用最好的Provider,可以减少的反应慢的Provider的调用,因为反应更容易累积并发的调用)

  4. actives,消费者端,最大并发调用限制,即当Consumer对一个服务的并发调用到上限后,新调用会Wait直到超时。在方法上配置(dubbo:method )则并发限制针对方法,在接口上配置(dubbo:service),则并发限制针对服务。


Provider上配置合理的Provider端属性
比如:


<dubbo:protocol threads="200" />
< dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService"
    executes="200" >
    <dubbo:method name="findAllPerson" executes="50" />
< /dubbo:service>


Provider上可以配置的Provider端属性有:

  1. threads,服务线程池大小

  2. executes,一个服务提供者并行执行请求上限,即当Provider对一个服务的并发调用到上限后,新调用会Wait(Consumer可能到超时)。在方法上配置(dubbo:method )则并发限制针对方法,在接口上配置(dubbo:service),则并发限制针对服务。

以上为网上的定义,在实际使用中当服务的消费方调用服务的提供方超时时,会抛出如下异常:

Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2016-07-20 16:27:34.873, end time: 2016-07-20 16:27:39.895, client elapsed: 0 ms, server elapsed: 5022 ms, timeout: 5000 ms, request: Request [id=438870, version=2.0.0, twoway=true, event=false, broken=false, data=http://www.mamicode.com/RpcInvocation [methodName=querySeatByCode, parameterTypes=[class java.lang.String, class java.lang.String], arguments=[99925788, A1], attachments={input=356, path=com.dfire.soa.turtle.service.ISeatService, interface=com.dfire.soa.turtle.service.ISeatService, timeout=5000, version=1.0.0H5_pressuretest}]], channel: /10.1.5.128:34443 -> /10.1.5.172:20880

网上通常的解决办法是调大超时时间,但是也可能是因为代码本身有潜在问题而造成dubbo超时。

比如:在dubbo消费方,调用了dubbo的提供方,此时事务是分部的,但如果自己的service方法中会用到一张表并去做update操作导致产生了行锁时,如果恰巧你又在之后调用了另一个会操作此表的dubbo服务,那么问题就产生了,你会在调dubbo服务的时候发生如上的超时异常,就是因为用spring aop声明式事务,在你service没有执行完时产生的行锁并没有释放,而你又在service里放入了需要操作此表的dubbo服务,这样当数据库的死锁还没有抛异常的时候,dubbo就已经抛异常了,因此这个超时异常其实坑很深。

本文出自 “菜鸟学习” 博客,请务必保留此出处http://biyusheng.blog.51cto.com/2626140/1913873

dubbo超时的深思