这块的代码debug了一个礼拜,一开始看Fegin创建源码的时候没注意到,是基于RxJava的响应式编程。分析栈桢的时候,有很多异步栈桢。由于只是想搞清楚如下配置的生效时机、以及失效情况,期间还看了一堆与此无关的源码,真的头大
先贴一下正确的超时配置
ribbon:
ReadTimeout: 3333
ConectTimeout: 2000
feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5555
服务降级流程:在Ribbon发送网络请求的同时,如果配置了hystrix降级,底层同时开启一个定时任务,间隔时间就是配置的hystrix超时时间,到点了,无论FeginClient有没有请求成功,都会先进行返回降级。对应的降级定时任务源码如下图。(里面的listener就是取的我们配置文件中的 timeoutInMilliseconds: 5555)。
断点位置:com.netflix.hystrix.util.HystrixTimer.addTimerListener()。
Ribbon超时流程:走正常的FeginClient发送请求的流程中,里面会进行读取我们配置的Ribbon超时时间(ribbon.ReadTimeout: 3333),Ribbon不配置的话默认是1s。贴一张debug的源码图如下。
断点位置:org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.execute()
整个过程是异步的,具体的实现底层用的是RxJava框架(发布、订阅模式)。如果正常的请求执行时间花了5s,但是在3s的时候,就被hystrix降级了,此时Ribbo在第5s的收到了返回结果,那么就会出一个诡异的现象,客户端收到的是降级请求,但是Fegin日志里面没报错,并且成功打印了本次的Fegin的request、reponse。因此我们的ribbon超时时间一般配置的比hystrix的超时时间小一点。
看源码大前提
首先我们要知道OpenFegin默认集成了Ribbon,也就是说只要我们使用了Fegin,Ribbon就一定会生效?答案是错误的,这个在之前的Cloud源码文章里面分析过了,只有当@FeginClient是通过注册中心调用服务的情况下,Ribbon才会生效。对应的Ribbon超时配置才会生效。
测试Fegin接口详情如下图。手动设置了服务提供方5s的超时
hystrix与ribbon超时的关系
先来说总结Ribbon超时相当于第一层壁垒,hystrix的超时相当于第二层壁垒。只有当(接口处理时间<Ribbon超时时间 && 接口处理时间< hystrix超时时间)时,接口才能正常响应,其他情况都会进行降级。
源码分析入口
具体的源码入口如下:feign.hystrix.HystrixInvocationHandler.invoke(),里面的run方法里面执行Ribbon负载均衡,返回服务调用请求的结果。getFallBack负责返回降级的结果。当Ribbon执行还没结束但是已经hystrix已经超时了,hystrix超时定时任务就会开启,触发getFallBack中的降级逻辑,然后返回结果。getRun、getFallback方法二选一返回。
里面的run方法走的是正常的流程,在 Spring Cloud OpenFegin(创建、发送请求)源码 一文中已经分析过了。getFallBack就是走的降级流程,看下图的栈桢
栈桢接着往下滑,可以看到getFallback就是降级定时任务触发的,和我分析的一样。到此关键节点的源码已经全贴出来了。其他具体的流程都在我脑子里哈哈哈哈哈哈,但是也怕忘,所以只贴关键代码方便日后回忆。
SpringCloud源码系列持续更新
- Spring Cloud OpenFegin(创建、发送请求)源码
- SpringCloud 之HttpClient、HttpURLConnection、OkHttpClient切换源码
- SpringCloud 源码系列之全局 Fegin 日志收集(okHttpClient、httpClient编码配置)