内容出自 图灵学院 我做完了作业,然后整理了整理代码,发了个博客
概念
在服务提供者和服务消费者上都可以配置服务超时时间,这两者是不一样的。
消费者调用一个服务,分为三步:
- 消费者发送请求(网络传输)
- 服务端执行服务
- 服务端返回响应(网络传输)
如果在服务端和消费端只在其中一方配置了timeout,那么没有歧义,表示消费端调用服务的超时时间,消费端如果超过时间还没有收到响应结果,则消费端会抛超时异常,但,服务端不会抛异常,服务端在执行服务后,会检查执行该服务的时间,如果超过timeout,则会打印一个超时日志。服务会正常的执行完。
如果在服务端和消费端各配了一个timeout,那就比较复杂了,假设
- 假如服务执行为5s
- 消费端timeout配置为3s
- 服务端timeout配置为6s
那么消费端调用服务时,消费端超过3秒回抛出超时异常,服务端一切正常(因为服务端超时配置的是6秒,没有超时)。
服务消费者调用超时之后会触发下面这样的异常
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
// timeout = 6000 定义服务的时候可以配置一个超时时间
(version = "default",timeout = 6000)
public class DefaultDemoService implements DemoService {
consumer
// 如果超过3秒还没调用成功,那么就会抛出异常, 如果你想等调用完成,那么就将timeout属性配置大一些
(version = "default", timeout = 3000)
private DemoService demoService;
代码地址
https://gitee.com/zjj19941/ZJJ_Dubbo.git 看 timeout 项目自己准备个zookeeper安装启动好了,改改配置文件zookeeper地址,然后依次启动provider和consumer,就可以看到效果
运行过程中控制台
consumer
因为consumer配置超时时间为3秒,但是provider处理要5秒多,consumer调用超时,抛出了这个异常 ,
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处理时间大一些,这样就不会因为等待时间过长调用超时了.
// 如果超过3秒还没调用成功,那么就会抛出异常, 如果你想等调用完成,那么就将timeout属性配置大一些
(version = "default", timeout = 10000)
private DemoService demoService;
provider
执行了timeout服务周瑜
执行了timeout服务周瑜
执行结束周瑜
执行了timeout服务周瑜
执行结束周瑜
执行结束周瑜
结果发现我consumer只是执行了一次,为什么provider控制台出现三条请求记录???
因为consumer调用超时了,跑了异常了,而dubbo有集群容错机制,如果调用失败了,dubbo还进行重试调用其它的provider.
为什么咱们这个日志打了三条请求记录,因为我这个案例只启动了一台provider,
consumer在调用provider调用失败之后,会进行重试机制,默认是两次,因为我这里只是启动了一台provider服务,所以dubbo重试机制的两次机会当然也就请求到了这唯一的provider机器上了.
所以这就是为什么provider有三条请求日志了,第一条请求日志是真正的请求,后两条请求日志是dobbo重试机制请求的日志.