Feign的超时时间如何设置,我研究了4种情况
大家好,我是三友~~
今天来聊一聊前段时间看到的一个面试题,也是在实际项目中需要考虑的一个问题,Feign的超时时间如何设置?
Feign的超时时间设置方式并不固定,它取决于Feign在项目中是如何使用的,不同的使用方式,超时时间设置方式也不大相同,甚至还可能有坑。
前置知识
由于文章会涉及到Feign的底层知识,如果不懂点Feign的基本概念的话,后面就看不下去了
所以为了方便不了解Feign的小伙伴也能够读得懂文章,这里我就简单地说说Feign的原理,点到为止,虽然不深入,但足够应付这篇文章了
Feign的作用
在项目中,我们经常需要调用第三方提供的Http接口,此时我们就可以使用一些Http框架来实现,比如HttpClient
public class HttpClientDemo {
public static void main(String[] args) throws Exception {
//创建一个HttpClient
HttpClient httpClient = HttpClientBuilder.create().build();
//构建一个get请求
HttpGet httpGet = new HttpGet("http://192.168.100.1:8080/order/1");
//发送请求,获取响应
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
//读出响应值
String response = EntityUtils.toString(httpEntity);
System.out.println("Response: " + response);
}
}
如果项目中只有一两个这种第三方接口这样写还行,但是一旦这种三方接口过多的话,每次都得这样组装参数,发送请求,写一堆同样的代码,就显然很麻烦了。
所以为了简化发送Http请求的开发,减少重复代码,Feign就出现了。
Feign是一个声明式的Http框架
当你需要调用Http接口时,你需要声明一个接口,加一些注解就可以了
而像组装参数、发送Http请求等重复性的工作都交给Feign来完成。
Feign的原理
虽然有了接口,但是仅仅有接口是不够的,因为接口又不能创建对象,我们得需要对象。
Feign为了方便我们为接口创建对象,提供的Feign.Builder
这个内部类

这个类的作用就是解析接口的上的注解,为接口生成一个动态代理对象,后面通过这个代理对象就可以发送请求了。
这个内部类有很多属性,这些属性都是Feign的核心组件。
在这些核心的组件中有一个叫Client
的,上图中我圈出来了。

这个Client
类划个重点,非常非常重要,本文讨论的东西跟他有密切关系。
它只有一个方法Response execute(Request request, Options options)
方法的第一个参数Request
就是封装了http请求的url、请求方法,请求头、请求体之类的参数

第二个参数Options
就是本文的主题,封装了超时时间。

返回值Response
就是封装了一些响应码status、响应头之类的

所以通过方法的参数和返回值也可以猜出来,这个Client
作用是用来组装Http请求参数,发送Http请求的
并且http请求超时时间是根据传给Client
的Options
参数来决定的

如果想更深一步了解Feign原理,可在公众号菜单栏springcloud分类中查看
Feign单独使用时超时时间设置
Feign本身就是一个http客户端,可独立使用,Feign提供了两种超时时间设置方式
1、通过Feign.Builder设置
前面提到,Feign.Builder
的作用是为接口的动态代理对象的
Feign.Builder
里面有很多属性,其中就有关于超时时间的属性Options

如果你不设置,那么超时时间就是默认的

默认的就是连接超时10s,读超时60s
所以可以通过设置Feign.Builder
中的options
来设置超时时间
来个demo
环境准备,就是一个简单的SpringBoot项目,引入一个Feign的依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
</dependencies>
声明接口 + 注解
public interface UserApi {
@RequestLine("GET /user/{userId}")
User queryUser(@Param("userId") Integer userId);
}
这里演示的是Feign原生的使用方式,脱离于SpringCloud环境,所以Spring的那些@GetMappring就不支持了,改用Feign本身提供的注解
测试代码
public class FeignDemo {
public static void main(String[] args) {
UserApi client = Feign.builder()
//设置连接和读超时间都是5s
.options(new Request.Options(5, TimeUnit.SECONDS, 5, TimeUnit.SECONDS, true))
.target(UserApi.class, "http://localhost:8088");
User user = client.queryUser(123);
}
}
这里面的请求路径都是不存在的,因为我们只关心传给Client
的Options
参数值
Client
在我们不设置的时候,就用默认的实现Client.Default

断点打到execute
方法的实现,运行,走起

结果就是我们设置的5s
2、在接口方法参数设置
除了在通过Feign.Builder时设置之外,Feign还支持在接口的方法参数上设置
此时你只需要在接口的方法上加一个Options
类型的参数
@RequestLine("GET /user/{userId}")
User queryUser(@Param("userId") Integer userId, Request.Options options);
这样在传参数时就可以设置超时时间了
User user = client.queryUser(123, new Request.Options(3, TimeUnit.SECONDS, 3, TimeUnit.SECONDS, true));
同样地,debug就可以看见我们设置的3s了

这两种设置超时时间的主要区别就是方法参数设置超时时间的优先级高于Feign.Builder设置的超时时间
用一张图来总结一下上面的关系

所以,如果你单独使用Feign的时候,你就可以通过如上的两种方式来设置超时时间。
SpringCloud下Feign单独使用超时时间设置
在SpringCloud环境下,只是对Feign进行了一层包装,所以即使没有Ribbon和注册中心,Feign也是可以单独使用的,但是用法有点变化
注解都换成SpringMVC的注解 接口上需要加@FeignClient注解 用@EnableFeignClients扫描这些接口
不过,默认情况下Feign还是需要结合Ribbon来使用的
如果你只想单独使用Feign,那么就设置一下@FeignClient注解的url属性,指定请求的地址和端口就可以了

所以,既然只是包装,前面提到的两种方式设置超时时间当然可以继续使用:
通过Feign.Builder 通过接口的方法参数
方法参数设置形式跟前面提到的一模一样,但是通过Feign.Builder来设置却不太一样
由于SpringCloud会自己创建Feign.Builder,不需要我们创建,所以在设置Options
时,Spring提供了两种快捷方式来设置
不过最终还是设置到Feign.Builder中
1、声明一个Options Bean
Spring在构建Feign.Builder
的时,会从容器中查找Options
这个Bean,然后设置到Feign.Builder
中
@Configuration
public class FeignConfiguration {
@Bean
public Request.Options options() {
return new Request.Options(8, TimeUnit.SECONDS, 8, TimeUnit.SECONDS, true);
}
}
此时debug就可以看到设置到Feign.Builder
的代码

这段代码在FeignClientFactoryBean中的configureUsingConfiguration方法中
2、配置文件中设置
除了声明Bean之外,Spring还提供了通过配置文件的方式配置,如下:
feign:
client:
config:
default:
connectTimeout: 10000
readTimeout: 10000
同样地,debug就可以看见

这段代码在FeignClientFactoryBean中的configureUsingConfiguration方法中
声明Bean和配置文件都可以设置,那么同时设置哪种优先级高呢?
如无特殊配置,遵守SpringBoot本身的配置规定
约定 > 配置 > 编码
所以基于这个规定,配置文件的配置优先级大于手动声明Bean的优先级。
到这,我们又学到了两种Spring为了方便我们设置Feign.Builder
提供的配置方式:
声明Options Bean 配置文件
把他们俩加到前面画的图中

所以,如果你使用了SpringCloud提供的方式来使用Feign,那么就可以通过声明Options
Bean和配置文件的方式更加方便地来设置超时时间
最终其实还是通过Feign.Builder
来设置的
SpringCloud下通过Ribbon来设置
当Feign配合Ribbon使用时,除了上面两种方式之外,还可以通过Ribbon来设置超时时间。
但是这里我不知道你会不会好奇
Ribbon不是负载均衡组件,怎么可以设置超时时间?
其实这跟Ribbon的定位有关,除了负载均衡组件之外,Ribbon也干发送Http请求的事,也就是不配合Feign,他照样可以发送http请求。
来个简单demo

解释一下上面的代码意思
第一步,设置user服务的两个服务实例地址 第二步,获取user服务对应的RestClient,这RestClient就可以用来发送http请求 第三步,构建一个http请求 第四步,就是发送http请求,以负载均衡的方式
这样,此时就会从两个服务实例中根据负载均衡选取一个服务地址发送http请求,
Ribbon既然可以发送Http请求,那么自然而然就可以设置超时时间
Feign在整合Ribbon的时候,为了统一配置,就默认将自己的超时时间交由Ribbon管理
所以,在默认情况下,Feign的超时时间可以由Ribbon配置
而Ribbon默认连接和读超时时间只有1s,所以在默认情况下,Feign的超时时间只有1s。

IClientConfig是Ribbon的配置类,Ribbon所有的配置都可以从IClientConfig中获取。
所以,在默认情况下,很容易就发生超时,不过我们可以通过配置文件修改即可
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000
你知道你发现没,上面说通过Ribbon设置Feign的超时时间,一直提到前面一直提到这个词
默认
什么情况下叫默认呢?
所谓的默认,就是当你不主动设置Feign的超时时间的时候,就是默认。
换句话说,一旦你通过上面说的那些配置方式设置Feign的超时时间,就不是默认了
此时通过Ribbon设置的超时时间就不会生效了
Feign是如何在默认情况下将超时时间交给Ribbon管理的?
要想回答这个问题,就得先搬出前面反复提到的Client接口了。
在SpringCloud的环境下,有一个Client的实现,叫LoadBalancerFeignClient

通过名字就可以看出,带有负载均衡的Client实现,负载均衡的实现肯定是交给Ribbon来实现的
所以当Feign配合Ribbon时用的就是这个Client实现
既然实现了Client
接口,那就看看execute
方法的实现逻辑

图中getClientConfig
方法就是判断使用Feign或者Ribbon配置的核心逻辑
核心的判断逻辑就是这一行
options == DEFAULT_OPTIONS
DEFAULT_OPTIONS
就是一个超时时间的常量

当上述判断条件成立时,就会通过this.clientFactory.getClientConfig(clientName)
获取到Ribbon配置
由于这是Ribbon的逻辑,这里就不深扒了,知道是这个意思就行
当条件不成立时,用Options
构建一个FeignOptionsClientConfig

FeignOptionsClientConfig
就是简单地将Options
配置读出来,设置到父类DefaultClientConfigImpl
超时时间配置上
DefaultClientConfigImpl
就算你不知道是什么也无所谓,你能看出的一件事就是,超时时间用的是传递给Client
的Options
参数
所以,综上,我们的问题就变得非常easy了,那就是什么时候
options == DEFAULT_OPTIONS
只有当这个条件成立时,才使用Ribbon的配置。
这里我们先来捋一捋前面提到的东西
前面我们反复提到,Client
的Options
最终只来自于两种配置
Feign.Builder 方法参数
所以DEFAULT_OPTIONS
这个Options
一定是通过上面两种方法中的其中一种设置的
而方法参数是不可能设置的成DEFAULT_OPTIONS
因为这是我们控制的,只要我们参数不传DEFAULT_OPTIONS
,那么永远都不可能是DEFAULT_OPTIONS
。
此时只剩下一种情况,那就是Spring在构建在Feign.Builder的时候,设置成DEFAULT_OPTIONS
。
通过查找DEFAULT_OPTIONS
的使用,我们可以追踪到这么一段代码

这不就是前面提到的通过声明Bean的方式来设置超时时间
不同的是它加了@ConditionalOnMissingBean
,这个注解就是说,一旦我们自己没有声明Options
,就用他这个Options
到这终于真像大白了。
我们不设置超时时间,Spring就会给Feign.Builder加一个DEFAULT_OPTIONS
这个Options
在执行的时候,发现是DEFAULT_OPTIONS
,说明我们没有主动设置过超是时间,就会使用Ribbon的超时时间。
为了方便理清上面的逻辑,这里整一张图

虽然Feign可以使用Ribbon的超时时间,但是Ribbon的配置的优先级是最最低的
方法参数 > Feign配置文件 > 声明Options > Ribbon配置
Feign or Ribbon配置用哪个好?
其实我个人更倾向于使用Ribbon的配置方式。
因为Ribbon除了可以设置超时时间之外,还可以配置重试机制、负载均衡等其它的配置
为了简化和统一管理配置,使用Ribbon来配置超时时间。
可能你会有疑问,Feign也支持重试机制,为什么不选择Feign?
这是因为Feign重试机制没有Ribbon的好
Ribbon重试的时候会换一个服务实例来重试,因为原来出错的可能不可用
而Feign并不会换一个服务实例重试,他并不知道上一次使用的是哪个服务实例,这就导致可能会出现在一个不可用的服务实例上多次重试的情况。
引入Hystrix时超时时间设置
如果你之前的确没有研究过关于Feign超时时间的配置关系,那么此时你应该有所收获了。
但是这就结束了么?
不,事情没那么简单。
如果你的项目中使用了Hystrix,那么就得小心前面说的那些配置了。
由于Hystrix跟Feign毕竟是一家人,所以当引入Hystrix时,Feign就跟之前不一样了。
Hystrix会去干一件事,那就是给每个Feign的http接口保护起来,毕竟Hystrix就是干保镖这个事的。
但是这没保护还好,一保护问题就不自觉地出现了。
Hystrix在保护的时候,一旦发现被保护的接口执行的时间超过Hystrix设置的最大时间,就直接进行降级操作。
怎么降级的,这里咱不关心,咱关心的是这个Hystrix超时的最大值是多少。
因为一旦这个时间小于Feign的超时时间,那么就会出现Http接口正在执行,也没有异常,仅仅是因为执行时间长,就被降级了。
而Hystrix的默认的超时时间的最大值就只有1s。

所以就算你Feign超时时间设置的再大,超过1s就算超时,然后被降级,太坑了。。
所以我们需要修改这个默认的超时时间的最大值,具体的配置项如下
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 30000
并且时间上大致要符合下面这个原则
Hystrix超时时间 >= (连接超时时间 + 读超时时间) * 重试次数
重试次数我们前面也提到了,虽然一般我们不设置,但是为了严谨还是得加上,因为一次Http接口的执行时间肯定跟重试次数有关,重试次数越多,时间就越长。
而连接超时时间 + 读超时时间设置方式,前面提到很多次,不论是通过Feign本身设置还是通过Ribbon来设置,都是可以的
总结
今天给大家扒了扒在不同使用条件下Feign的超时时间设置,总结起来大致如下:
单独使用Feign时:通过 Feign.Builder
和方法参数SpringCloud环境下单独使用Feign:方法参数、配置文件、声明 Options
Bean跟Ribbon配合使用:通过Ribbon的超时参数设置 跟Hystrix配合使用:修改默认的超时时间,尽量符合 Hystrix超时时间 >= (连接超时时间 + 读超时时间) * 重试次数
如果本篇文章对你所有帮助,欢迎转发、点赞、收藏、在看,非常感谢。
往期热门文章推荐
扫码或者搜索关注公众号 三友的java日记 ,及时干货不错过,公众号致力于通过画图加上通俗易懂的语言讲解技术,让技术更加容易学习,回复 面试 即可获得一套面试真题。

Feign的超时时间如何设置,我研究了4种情况的更多相关文章
- Spring Cloud之Feign客户端超时时间配置
关于雪崩效应: 默认情况下tomcat只有一个线程去处理客户端发送的所有请求.高并发情况下,如果客户端请求都在同一接口,tomcat的所有线程池去处理,导致其他接口服务访问不了,等待. Tomcat有 ...
- HttpClient不同版本超时时间的设置
引自 https://www.cnblogs.com/hisunhyx/p/5028391.html 3.X是这样的 HttpClient client=new DefaultHttpClient() ...
- 【轮询】【ajax】【js】【spring boot】ajax超时请求:前端轮询处理超时请求解决方案 + spring boot服务设置接口超时时间的设置
场景描述: ajax设置timeout在本机测试有效,但是在生产环境等外网环境无效的问题 1.ajax的timeout属性设置 前端请求超时事件[网络连接不稳定时候,就无效了] var data = ...
- 系统session超时时间的设置
一个网站系统:当你停止活动一段时间后,系统自动退出 三种方式设置: 1. 在server.xml中定义context时采用如下定义: <Context path="/livsorder ...
- webuploader超时时间timeout设置
参考:http://www.codingwhy.com/view/841.html 备注下!
- springcloud之Feign、ribbon设置超时时间和重试机制的总结
一 超时时间配置 如果在一个微服务当中对同一个接口同时配置了Hystrix与ribbon两个超时时间,则在接口调用的时候,两个计时器会同时读秒. 比如,访问一个接口需要2秒,你的ribbon配置的超时 ...
- spring cloud各种超时时间设置
如果是zuul(网关)的超时时间需要设置zuul.hystrix.ribbon等三部分: #zuul超时设置#默认1000zuul.host.socket-timeout-millis=2000#默认 ...
- hystrix ,feign,ribbon的超时时间配置,以及原理分析
背景,网上看到很多关于hystrix的配置都是没生效的,如: 一.先看测试环境搭建: order 服务通过feign 的方式调用了product 服务的getProductInfo 接口 //---- ...
- nginx限制上传大小和超时时间设置说明/php限制上传大小
现象说明:在服务器上部署了一套后台环境,使用的是nginx反向代理tomcat架构,在后台里上传一个70M的视频文件,上传到一半就失效了! 原因是nginx配置里限制了上传文件的大小 client_m ...
- 接口调试工具ApiPost的发送超时时间设置方法
有部分使用ApiPost的同学反应:发送接口调试时,响应超时时间设置的太短导致接口访问失败,怎么设置呢? 就连百度也有很多人在搜: 今天就来说一说. ApiPost简介: ApiPost是一个支持团队 ...
随机推荐
- 2022-02-17:寻找最近的回文数。 给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。 “最近的”定义为两个整数差的绝对值最小。 示例 1: 输
2022-02-17:寻找最近的回文数. 给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身).如果不止一个,返回较小的那个. "最近的"定义为两个整数差的绝对值最 ...
- uniapp开发企业微信应用中的定位问题记录
项目背景:开发工具为HBuilderX,框架为uniapp,开发移动端的Web应用,在企业微信中使用(自建应用),Web开发的应用,不是小程序. 需求点:获取用户当前的位置信息,技术流程包括以下几个环 ...
- 淘宝召回模型MGDSPR-学习笔记
一 简介 本文是论文Embedding-based Product Retrieval in Taobao Search的学习笔记 1 整体概览 电商无处不在,从大规模语料库里面检索出兼顾相关性和用户 ...
- 【问题解决】 网关代理Nginx 301暴露自身端口号
一般项目上常用Nginx做负载均衡和静态资源服务器,本案例中项目上使用Nginx作为静态资源服务器出现了很奇怪的现象,我们一起来看看. "诡异"的现象 部署架构如下图,Nginx作 ...
- 使用Flask和Django构建Web应用程序:现代Web应用程序框架
目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 2.3 相关技术比较 3. 实现步骤与流程 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成 ...
- ResNet模型:在计算机视觉任务中实现深度学习
目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 3. 实现步骤与流程 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成与测试 4. 示例与应 ...
- C# Collections
1. Generic 1.1 List<T> No need to say this is the most commonly used data structure in C# coll ...
- NextJS项目的部署以及多环境的实现
背景 开发了个Next项目,将部署过程记录一下.另外由于项目准备了两个服务器分别作为开发自测的开发环境和交付给客户的生产环境使用:因此也介绍一下NextJS项目中多环境的配置. 项目结构 计划是让Ng ...
- 手把手教你自定义自己SpringBoot Starter组件源码剖析
我们知道SpringBoot Starter也就是启动器.是SpringBoot组件化的一大优点.基于这个思想,基于这个思想SpringBoot 才变得非常强大,官方给我们提供很多开箱即用的启动器. ...
- hexo博客主题,git上传,报错Template render error的解决方案
报错信息 INFO Start processing FATAL Something's wrong. Maybe you can find the solution here: http://hex ...