在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端属性
原因如下:
- 作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
- 在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值。否则,Consumer会使用Consumer端的全局设置,这对于Provider不可控的,并且往往是不合理的
- 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端属性有:
- timeout,方法调用超时
- retries,失败重试次数,缺省是2(表示加上第一次调用,会调用3次)
- loadbalance,负载均衡算法(有多个Provider时,如何挑选Provider调用),缺省是随机(random)。还可以有轮训(roundrobin)、最不活跃优先(leastactive,指从Consumer端并发调用最好的Provider,可以减少的反应慢的Provider的调用,因为反应更容易累积并发的调用)
- 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端属性有:
- threads,服务线程池大小
- 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=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就已经抛异常了,因此这个超时异常其实坑很深。