内容出自 图灵学院 我学完了 整理了整理发了个博客

概念

在服务提供者和服务消费者上都可以配置服务超时时间,这两者是不一样的。

消费者调用一个服务,分为三步:

  1. 消费者发送请求(网络传输)
  2. 服务端执行服务
  3. 服务端返回响应(网络传输)

如果在服务端和消费端只在其中一方配置了timeout,那么没有歧义,表示消费端调用服务的超时时间,消费端如果超过时间还没有收到响应结果,则消费端会抛超时异常,服务端不会抛异常,服务端在执行服务后,会检查执行该服务的时间,如果超过timeout,则会打印一个超时日志。服务会正常的执行完。

如果在服务端和消费端各配了一个timeout,那就比较复杂了,假设

  1. 假如服务执行为5s
  2. 消费端timeout配置为3s
  3. 服务端timeout配置为6s

那么消费端调用服务时,消费端超过3秒回抛出超时异常,服务端一切正常(因为服务端超时配置的是6秒,没有超时)。

服务消费者调用超时之后会触发下面这样的异常

  1. Caused by: java.util.concurrent.ExecutionException: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2021-12-11 21:04:11.590, end time: 2021-12-11 21:04:14.620, client elapsed: 1 ms, server elapsed: 3029 ms, timeout: 3000 ms, request: Request [id=2, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=sayHello, parameterTypes=[class java.lang.String], arguments=[周瑜], attachments={path=com.tuling.DemoService, remote.application=dubbo-consumer-demo, interface=com.tuling.DemoService, version=default, timeout=3000}]], channel: /172.16.10.1:57506 -> /172.16.10.1:20880

配置方式

provider

  1. // timeout = 6000 定义服务的时候可以配置一个超时时间
  2. @Service(version = "default",timeout = 6000)
  3. public class DefaultDemoService implements DemoService {

consumer

  1. // 如果超过3秒还没调用成功,那么就会抛出异常, 如果你想等调用完成,那么就将timeout属性配置大一些
  2. @Reference(version = "default", timeout = 3000)
  3. private DemoService demoService;

代码地址

https://gitee.com/zjj19941/ZJJ_Dubbo.git
看 timeout 项目自己准备个zookeeper安装启动好了,改改配置文件zookeeper地址,然后依次启动provider和consumer,就可以看到效果

运行过程中控制台

consumer

因为consumer配置超时时间为3秒,但是provider处理要5秒多,consumer调用超时,抛出了这个异常 ,

  1. Caused by: java.util.concurrent.ExecutionException: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2021-12-11 21:04:11.590, end time: 2021-12-11 21:04:14.620, client elapsed: 1 ms, server elapsed: 3029 ms, timeout: 3000 ms, request: Request [id=2, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=sayHello, parameterTypes=[class java.lang.String], arguments=[周瑜], attachments={path=com.tuling.DemoService, remote.application=dubbo-consumer-demo, interface=com.tuling.DemoService, version=default, timeout=3000}]], channel: /172.16.10.1:57506 -> /172.16.10.1:20880

如果你不想抛异常,并且让请求调用正常,那么就需要调整consumer那边配置的timeout属性,给timeout属性调整大一点,至少要比provider处理时间大一些,这样就不会因为等待时间过长调用超时了.

  1. // 如果超过3秒还没调用成功,那么就会抛出异常, 如果你想等调用完成,那么就将timeout属性配置大一些
  2. @Reference(version = "default", timeout = 10000)
  3. private DemoService demoService;

provider

  1. 执行了timeout服务周瑜
  2. 执行了timeout服务周瑜
  3. 执行结束周瑜
  4. 执行了timeout服务周瑜
  5. 执行结束周瑜
  6. 执行结束周瑜

结果发现我consumer只是执行了一次,为什么provider控制台出现三条请求记录???
因为consumer调用超时了,跑了异常了,而dubbo有集群容错机制,如果调用失败了,dubbo还进行重试调用其它的provider.
为什么咱们这个日志打了三条请求记录,因为我这个案例只启动了一台provider,
consumer在调用provider调用失败之后,会进行重试机制,默认是两次,因为我这里只是启动了一台provider服务,所以dubbo重试机制的两次机会当然也就请求到了这唯一的provider机器上了.
所以这就是为什么provider有三条请求日志了,第一条请求日志是真正的请求,后两条请求日志是dobbo重试机制请求的日志.