dubbo提供在provider和consumer端,都提供了超时(timeout)和重试(retries)的参数配置。


配置方式

provider端在<dubbo:service>中配置,consumer端在<dubbo:reference>中配置。

默认值

timeout默认值为1000,单位毫秒,表示超时时间是1秒;

retries默认值为2,表示重试2次,加上本身调用1次,一共有3次调用;

org.apache.dubbo.common.Constants类可以找到:

public static final int DEFAULT_TIMEOUT = 1000;
public static final int DEFAULT_RETRIES = 2;

优先级

consumer端配置优先于provider端配置


通过一个例子来对这2个参数进行详细学习和解读。

建立如下工程结构:

其中:

demo-consumer为consumer端应用(SpringBoot工程)

demo-provider为provider端父工程,它下面有2个子工程,

    demo-interface为dubbo服务接口定义

    demo-service为provider端应用(SpringBoot工程),实现了demo-interface接口,

demo-interface里接口定义:

public interface HelloService {

    String hello(String name);
}

定义了1个HelloService接口,里面一个hello方法,请求参数为1个String,返回String。

在demo-service里对该接口的实现类:

@Service("helloService")
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String name) {
System.out.println("hello begin=>" + name);
System.out.println("hello end=>" + name);
return "hello " + name;
}
}

demo-service中的dubbo-demo-provider.xml定义:

<dubbo:service ref="helloService" interface="com.cdfive.demo.service.HelloService"  />

demo-consumer中的dubbo-demo-consumer.xml定义:

<dubbo:reference id="helloService" interface="com.cdfive.demo.service.HelloService" />

为了通过浏览器输入请求地址访问,在demo-consumer定义了一个Controller:

@RequestMapping("test")
@RestController
public class TestController { @Autowired
private HelloService helloService; @RequestMapping("hello")
public String hello(String name) {
return helloService.hello(name);
}
}

这样我们就可以通过浏览器里访问http://localhost:8081/test/hello?name=xxx,来调用dubbo接口:HelloService#hello

demo-consumer的启动类:

@Slf4j
@ImportResource("classpath:config/applicationContext.xml")
@SpringBootApplication(scanBasePackages = "com.cdfive")
public class DemoConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoConsumerApplication.class, args);
log.info("demo consumer started");
}
}

demo-service的启动类:

@Slf4j
@ImportResource("classpath:config/applicationContext.xml")
@SpringBootApplication(scanBasePackages = "com.cdfive")
public class DemoProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DemoProviderApplication.class, args);
log.info("demo provider started");
}
}

OK,准备工作完毕。

把provider端和consumer端应用都启起来,浏览器中访问:http://localhost:8081/test/hello?name=cdfive

可以看到,浏览器中显示:

hello cdfive

在demo-service的控制台显示:

hello begin=>cdfive

hello end=>cdfive

前面提到,timeout默认是1000,就是1秒超时。这里我们修改HelloServiceImpl的实现,通过Thread.sleep(2000)模拟业务方法超时,休眠2s:

@Service("helloService")
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String name) {
System.out.println("hello begin=>" + name); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("hello end=>" + name);
return "hello " + name;
}
}

重启demo-service,F5刷新浏览器再次访问:http://localhost:8081/test/hello?name=cdfive

case 1: 默认情况,provider和consumer端的timeout和retires均不设置,使用默认值

观察输出结果

浏览器:

There was an unexpected error (type=Internal Server Error, status=500).

Failed to invoke the method hello in the service com.cdfive.demo.service.HelloService. Tried 3 times of the providers....

provider端:

hello begin=>cdfive

hello begin=>cdfive

hello end=>cdfive

hello begin=>cdfive

hello end=>cdfive

hello end=>cdfive

consumer端:

[ WARN ] [2019-01-01 14:52:03,007] [DubboClientHandler-192.168.1.100:20001-thread-2] com.alibaba.dubbo.remoting.exchange.support.DefaultFuture [71] - [DUBBO] The timeout response finally returned at 2019-01-01 14:52:03.007, response Response [id=6, version=null, status=20, event=false, error=null, result=RpcResult [result=hello cdfive, exception=null]], channel: /192.168.1.100:61755 -> /192.168.1.100:20001, dubbo version: 2.6.0, current host: 192.168.1.100

[ WARN ] [2019-01-01 14:52:04,008] [DubboClientHandler-192.168.1.100:20001-thread-2] com.alibaba.dubbo.remoting.exchange.support.DefaultFuture [71] - [DUBBO] The timeout response finally returned at 2019-01-01 14:52:04.008, response Response [id=7, version=null, status=20, event=false, error=null, result=RpcResult [result=hello cdfive, exception=null]], channel: /192.168.1.100:61755 -> /192.168.1.100:20001, dubbo version: 2.6.0, current host: 192.168.1.100

[ ERROR] [2019-01-01 14:52:04,011] [http-nio-8081-exec-6] org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] [182] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method hello in the service com.cdfive.demo.service.HelloService. Tried 3 times of the providers [192.168.1.100:20001] (1/1) from the registry localhost:2181 on the consumer 192.168.1.100 using the dubbo version 2.6.0. Last error is: Invoke remote method timeout. method: hello, provider: dubbo://192.168.1.100:20001/com.cdfive.demo.service.HelloService?anyhost=true&application=demo_consumer&check=false&default.check=false&dubbo=2.6.0&generic=false&interface=com.cdfive.demo.service.HelloService&methods=hello&pid=7032&register.ip=192.168.1.100&remote.timestamp=1546325119243&side=consumer&timestamp=1546324847011, cause: Waiting server-side response timeout. start time: 2019-01-01 14:52:03.006, end time: 2019-01-01 14:52:04.008, client elapsed: 1 ms, server elapsed: 1001 ms, timeout: 1000 ms, request: Request [id=8, version=2.0.0, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=hello, parameterTypes=[class java.lang.String], arguments=[cdfive], attachments={path=com.cdfive.demo.service.HelloService, interface=com.cdfive.demo.service.HelloService, version=0.0.0}]], channel: /192.168.1.100:61755 -> /192.168.1.100:20001] with root cause

com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout. start time: 2019-01-01 14:52:03.006, end time: 2019-01-01 14:52:04.008, client elapsed: 1 ms, server elapsed: 1001 ms, timeout: 1000 ms, request: Request [id=8, version=2.0.0, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=hello, parameterTypes=[class java.lang.String], arguments=[cdfive], attachments={path=com.cdfive.demo.service.HelloService, interface=com.cdfive.demo.service.HelloService, version=0.0.0}]], channel: /192.168.1.100:61755 -> /192.168.1.100:20001

at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:134)

at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:111)

at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:95)

at com.alibaba.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:142)

at com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:73)

at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:74)

at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)

at com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:53)

at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)

at com.alibaba.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:47)

at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)

at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:52)

at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:77)

at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:232)

at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:70)

at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:51)

at com.alibaba.dubbo.common.bytecode.proxy0.hello(proxy0.java)

at com.cdfive.demo.controller.TestController.hello(TestController.java:21)

浏览器打印了异常信息,其中Tried 3 times of the providers表明尝试了3次调用;

provider打印了3次请求调用情况,注意到begin和end不是按顺序的,也就是说上1个调用没执行完,因为1秒超时时间到了,又开始了新的一次重试,而前面的调用并未终止;

consumer打印了3次WARN ...[DUBBO] The timeout response...,和一次ERROR,错误信息跟浏览器看到的一致,只是多了堆栈信息。

总结:

在不设置timeout和retries的时候,如果provider端接口一直出现超时,provider端会调用3次,而日志中没有任何警告或错误信息;

consumer端虽然重试了2次,加本身调用的1次,一共发起3次调用,如果provider3次全部超时,consumer端会打印超时异常信息;

provider端日志中没有任何警告或错误信息不利于发现问题;前面的调用并未终止,如果是非查询类接口且接口没有实现幂等性时,可能产生重复数据

case 2: provider端retries=0,consumer端不设置

重启并访问,浏览器中仍然是错误信息,但是Tried 1 times of the providers,表示只调用了1次 ;

provider端仅打印了1次调用:

hello begin=>cdfive

hello end=>cdfive

consumer端打印1次WARN、1次ERROR

总结:

在provider端设置retries=0已经生效,接口仅调用了1次;

case 3: provider端retries=0,consumer端retries=1

重启并访问,浏览器中仍然是错误信息,但是Tried 2 times of the providers,表明调用了2次 ;

provider端打印了2次调用,consumer打印了2次WARN、1次ERROR

总结:

consumer的retries优先级较高,两端都设置的情况下,以consumer端的retries为准

case 4: provider端timeout=3000, retries=0,consumer端retries=0

接下来我们把重试都关闭(即都设置为0),来看看timeout的情况,这里设置为3秒,因为方法休眠2s;

重启并访问:

浏览器正常输出hello cdfive,provider输出请求参数,consumer没有输出;

总结:

provider端设置timeout已生效。

case 5: provider端timeout=1000, retries=0,consumer端retries=0

provider端的超时设置为小于接口执行时间;

重启并访问:

跟case 1很像,因为重试为0,所以只调用了1次,唯一不同的provider端日志里多了1次WARN

[ WARN ] [2019-01-01 15:19:49,482] [DubboServerHandler-192.168.1.100:20001-thread-2] com.alibaba.dubbo.rpc.filter.TimeoutFilter [71] - [DUBBO] invoke time out. method: hello arguments: [cdfive]...

这是dubbo自带的filter类TimeoutFilter输出的。

总结:

provider端设置了timeout,如果接口调用超时,provider会打印WRAN信息。

case 6: provider端timeout=1000, retries=0,consumer端timeout=3000, retries=0

这里provider端的1秒小于接口方法的2秒,而consumer设置的3秒大于2秒,

重启并访问:

浏览器成功输出hello cdfive,provider输出请求参数,并打印了1次WARN,consumer没有输出;

总结:

consumer的timeout优先级较高,两端都设置的情况下,以consumer端的timeout为准


参考dubbo官网的文档,并结合工作中项目实践,对超时和重试这2个参数做个总结:

1.超时(timeout)默认1000毫秒,重试(retries)默认2次(即一共调用3次);

2.provider端在<dubbo:service>中配置,consumer端在<dubbo:reference>中配置,consumer端的配置会覆盖provider配置;

3.超时(timeout)建议在provider端配置,因为作为提供方,它更清楚自己接口的耗时情况,并且provider端设置了timeout,在日志中有TimeoutFilter的WARN信息;

4.在provider端一般接口timeout设置为5秒或者10秒,如果是复杂查询、导出报表、调用第三方接口、本身是最上游的接口等,根据情况考虑设置大一点;

5.在consumer端配置设置timeout会覆盖provider设置,但有时设置timeout能够让consumer快速失败,而不因为下游provider服务接口的问题拖垮consumer本身;

6.retries建议在provider端设置为0,consumer根据情况也可以设置为0,因为重试可能因非幂等性原因导致重复数据,并且超时情况即便重试成功consumer端可能也收不到成功响应;


参考:

http://dubbo.apache.org/zh-cn/docs/user/recommend.html

http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-service.html

http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-reference.html

dubbo学习笔记(一)超时与重试的更多相关文章

  1. 别人的dubbo学习笔记

    本文转载自:http://blog.csdn.net/tao_qq/article/details/49952229 学习dubbo,开始做一些笔记. 1> 启动dubbo-admin模块的时候 ...

  2. Dubbo学习笔记(二) Dubbo的基本配置

    Check启动检查 根据之前的学习,我们简单理解的Dubbo远程调用的基本流程,服务提供者注册到注册中心,然后服务消费者通过监听注册中心达到远程调用的目的,那么如果注册中心中没有消费者对应的接口会怎么 ...

  3. Dubbo 学习笔记

    分布式基础理论 1. 什么是分布式系统? 分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个系统 2. 应用架构演变 单一应用架构 当网站流量很小时,只需一个应用,将所有功能都部署在一起 ...

  4. dubbo学习笔记

    一.zookeeper在Dubbo中扮演角色 流程:1.服务提供者启动时向/dubbo/com.foo.BarService/providers目录下写入URL2.服务消费者启动时订阅/dubbo/c ...

  5. Dubbo学习笔记8:Dubbo的线程模型与线程池策略

    Dubbo默认的底层网络通讯使用的是Netty,服务提供方NettyServer使用两级线程池,其中 EventLoopGroup(boss) 主要用来接受客户端的链接请求,并把接受的请求分发给 Ev ...

  6. Dubbo学习笔记11:使用Dubbo中需要注意的一些事情

    指定方法异步调用 前面我们讲解了通过设置ReferenceConfig的setAsync()方法来让整个接口里的所有方法变为异步调用,那么如何指定某些方法为异步调用呢?下面讲解下如何正确地设置默写方法 ...

  7. Dubbo学习笔记7:Dubbo的集群容错与负载均衡策略

    Dubbo的集群容错策略 正常情况下,当我们进行系统设计时候,不仅要考虑正常逻辑下代码该如何走,还要考虑异常情况下代码逻辑应该怎么走.当服务消费方调用服务提供方的服务出现错误时候,Dubbo提供了多种 ...

  8. Dubbo学习笔记5:Dubbo整体框架分析

    Dubbo的分层架构 本文将简单介绍Dubbo的分层架构设计,如下图是Dubbo官方的整体架构图: Dubbo官方提供的该架构图很复杂,一开始我们没必要深入细节,下面我们简单介绍下其中的主要模块. 其 ...

  9. Dubbo学习笔记1:使用Zookeeper搭建服务治理中心

    Zookeeper是Apache Hadoop的子项目,是一个树形的目录服务,支持变更推送,适合作为Dubbo服务的注册中心,工业强度较高,推荐生成环境使用. , 下面结合上图介绍Zookeeper在 ...

随机推荐

  1. 微信小程序开发(七)获取手机网络类型

    // succ.wxml <view>手机网络状态:{{netWorkType}}</view> // succ.js var app = getApp() Page({ da ...

  2. Python 实现快递查询

    实现效果: 源代码: import urllib.request import json import msvcrt kd_dict = {1:'shentong',2:'youzhengguonei ...

  3. Caffe---自带工具进行网络结构(xxx.prototxt)可视化

    Caffe---自带绘图工具(draw_net.py)绘制网络结构图(xxx.prototxt) 目录: 一,安装依赖库. 二,draw_net.py使用说明. 正文: 一,安装依赖库. 在绘制之前, ...

  4. java线程基础巩固---如何实现一个自己的显式锁Lock

    拋出synchronized问题: 对于一个方法上了同锁如果被一个线程占有了,而假如该线程长时间工作,那其它线程不就只能傻傻的等着,而且是无限的等这线程工作完成了才能执行自己的任务,这里来演示一下这种 ...

  5. Redis长短链接的区别

    本文介绍了phpredis中与redis建立连接的两种方式:connect(短连接)和pconnect(长连接)的区别. 问题背景: 项目采用LNMP架构,考虑到数据访问性能问题,因此使用redis来 ...

  6. WPF DevExpress ChartControl使用之PieChart

    饼状图要比XYDiagram要简单一点,大体上也是那些东西,没有了X.Y坐标轴,也就没有了第二坐标,要简单一点.PieChartControl.xaml <UserControl x:Class ...

  7. API接口防止参数篡改和重放攻击

    {近期领导要求我对公司业务的支付类的ocr接口做研究,是否存在支付接口重放攻击,so.....} API重放攻击(Replay Attacks)又称重播攻击.回放攻击.他的原理就是把之前窃听到的数据原 ...

  8. BZOJ 2178: 圆的面积并 (辛普森积分)

    code #include <set> #include <cmath> #include <cstdio> #include <cstring> #i ...

  9. python--openCV--视频处理

    编码格式 视频容器中,一般有视频和音频数据,它们采取的编码方式不一样. 视频常见的编码方式通常有: x264.h264.mpeg-4 音频常见的编码方式通常有: mp3.AAC.flac 编码的目的主 ...

  10. android&ios区别

    转自(只讲干货的老张) 面试中经常提问到一个点,就是做手机测试绕不去的点,那就是Android和ios的区别.这篇文章只做一些比较重要的点讲一下,太深入部分就不讲了,毕竟我做的是测试,而Android ...