RPC

Dubbo超时与重试

Dubbo超时与重试策略探究

Posted by yyconstantine on January 9, 2020

Dubbo超时与重试

Dubbo提供了多种配置方式:XML、properties、spring-boot-starter,下面均以starter方式进行演示。


超时策略

由于dubbo分为Provider和Consumer,其各自维护了一套超时策略,以dubbo.provider.timeoutdubbo.consumer.timeout表示。

有一个可能会疑惑的点是:如果我同时在Consumer和Provider配置了timeout,那么最终在Consumer端进行rpc调用时,会以哪个超时时间为准呢?

答案是:以服务端的超时时间为准。

其实也很好理解,我们以一次Consumer-Provider的调用举例:

  • 请求通过网关进入Consumer,此时Consumer开始计时超时时间
  • Consumer在同步过程中发起rpc调用,进入Provider,并等待Provider返回,此时Provider开始计时超时时间,此时我们假设Provider执行较慢
    • 当Consumer达到规定超时时间,则Consumer不再关心Provider是否返回结果,直接返回response并中断请求
    • 当Provider达到规定超时时间,则Consumer会收到一个RpcException,Consumer收到后若未到超时时间则继续执行同步业务逻辑,直到同步返回或Consumer超时;而Provider抛出RpcException后仍然继续执行直到方法结束,或本身作为Consumer继续调用其他Provider。禁止套娃
  • PS:dubbo.*.timeout缺省值为1000ms,我们需要根据业务进行合理设置

重试策略

重试同样分为Provider和Consumer的属性,dubbo官方建议优先进行Provider端的配置,因为服务提供者比服务消费者更清楚自己的性能。

那么一般的配置(整个service)如下:

dubbo:
	provider:
		retries: -1 // 由于dubbo的bug,我们设置0时其实仍然会进行2次重试,-1则不再进行重试
@org.apache.dubbo.config.annotation.Service(
    retries = -1
)
public class ApiServiceImpl implements ApiService {}

方法/接口级别的配置如下:

@org.apache.dubbo.config.annotation.Service(
    retries = -1,
    parameters = {
        "method1.retries", "-1", "method1.timeout", "3000"
        "method2.retries", "0"
    }
)
public class ApiServiceImpl implements ApiService {
    void method1() {}
    void method2() {}
}

由于我们的服务有多种接口,所以一般不建议一棒子打死(整个服务设置不进行重试,毕竟rpc调用存在超时的可能),我们通过设置接口重试次数对需要保证幂等的接口进行规范,可以一定程度上保证接口幂等,但为了做到接口幂等,我们不应该仅依赖dubbo的重试机制