当前位置:首页 > 科技  > 软件

Feign如何设置超时时间,不同情况下还真不一样

来源: 责编: 时间:2023-08-14 22:00:37 219观看
导读大家好,我是三友~~今天来聊一聊前段时间看到的一个面试题,也是在实际项目中需要考虑的一个问题,Feign的超时时间如何设置?Feign的超时时间设置方式并不固定,它取决于Feign在项目中是如何使用的,不同的使用方式,超时时间设置

大家好,我是三友~~QeK28资讯网——每日最新资讯28at.com

今天来聊一聊前段时间看到的一个面试题,也是在实际项目中需要考虑的一个问题,Feign的超时时间如何设置?QeK28资讯网——每日最新资讯28at.com

Feign的超时时间设置方式并不固定,它取决于Feign在项目中是如何使用的,不同的使用方式,超时时间设置方式也不大相同,甚至还可能有坑。QeK28资讯网——每日最新资讯28at.com

前置知识

由于文章会涉及到Feign的底层知识,如果不懂点Feign的基本概念的话,后面就看不下去了QeK28资讯网——每日最新资讯28at.com

所以为了方便不了解Feign的小伙伴也能够读得懂文章,这里我就简单地说说Feign的原理,点到为止,虽然不深入,但足够应付这篇文章了QeK28资讯网——每日最新资讯28at.com

Feign的作用

在项目中,我们经常需要调用第三方提供的Http接口,此时我们就可以使用一些Http框架来实现,比如HttpClientQeK28资讯网——每日最新资讯28at.com

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);    }}

如果项目中只有一两个这种第三方接口这样写还行,但是一旦这种三方接口过多的话,每次都得这样组装参数,发送请求,写一堆同样的代码,就显然很麻烦了。QeK28资讯网——每日最新资讯28at.com

所以为了简化发送Http请求的开发,减少重复代码,Feign就出现了。QeK28资讯网——每日最新资讯28at.com

Feign是一个声明式的Http框架QeK28资讯网——每日最新资讯28at.com

当你需要调用Http接口时,你需要声明一个接口,加一些注解就可以了QeK28资讯网——每日最新资讯28at.com

而像组装参数、发送Http请求等重复性的工作都交给Feign来完成。QeK28资讯网——每日最新资讯28at.com

Feign的原理

虽然有了接口,但是仅仅有接口是不够的,因为接口又不能创建对象,我们得需要对象。QeK28资讯网——每日最新资讯28at.com

Feign为了方便我们为接口创建对象,提供的Feign.Builder这个内部类QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

这个类的作用就是解析接口的上的注解,为接口生成一个动态代理对象,后面通过这个代理对象就可以发送请求了。QeK28资讯网——每日最新资讯28at.com

这个内部类有很多属性,这些属性都是Feign的核心组件。QeK28资讯网——每日最新资讯28at.com

在这些核心的组件中有一个叫Client的,上图中我圈出来了。QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

这个Client类划个重点,非常非常重要,本文讨论的东西跟他有密切关系。QeK28资讯网——每日最新资讯28at.com

它只有一个方法Response execute(Request request, Options options)QeK28资讯网——每日最新资讯28at.com

方法的第一个参数Request就是封装了http请求的url、请求方法,请求头、请求体之类的参数QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

第二个参数Options就是本文的主题,封装了超时时间。QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

返回值Response就是封装了一些响应码status、响应头之类的QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

所以通过方法的参数和返回值也可以猜出来,这个Client作用是用来组装Http请求参数,发送Http请求的QeK28资讯网——每日最新资讯28at.com

并且http请求超时时间是根据传给Client的Options参数来决定的QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

如果想更深一步了解Feign原理,可在公众号菜单栏springcloud分类中查看QeK28资讯网——每日最新资讯28at.com

Feign单独使用时超时时间设置

Feign本身就是一个http客户端,可独立使用,Feign提供了两种超时时间设置方式QeK28资讯网——每日最新资讯28at.com

1、通过Feign.Builder设置

前面提到,Feign.Builder的作用是为接口的动态代理对象的QeK28资讯网——每日最新资讯28at.com

Feign.Builder里面有很多属性,其中就有关于超时时间的属性OptionsQeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

如果你不设置,那么超时时间就是默认的QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

默认的就是连接超时10s,读超时60sQeK28资讯网——每日最新资讯28at.com

所以可以通过设置Feign.Builder中的options来设置超时时间QeK28资讯网——每日最新资讯28at.com

来个demoQeK28资讯网——每日最新资讯28at.com

环境准备,就是一个简单的SpringBoot项目,引入一个Feign的依赖QeK28资讯网——每日最新资讯28at.com

<dependencies>    <dependency>        <groupId>org.springframework.cloud</groupId>        <artifactId>spring-cloud-starter-openfeign</artifactId>        <version>2.2.5.RELEASE</version>    </dependency></dependencies>

声明接口 + 注解QeK28资讯网——每日最新资讯28at.com

public interface UserApi {    @RequestLine("GET /user/{userId}")    User queryUser(@Param("userId") Integer userId);}

这里演示的是Feign原生的使用方式,脱离于SpringCloud环境,所以Spring的那些@GetMappring就不支持了,改用Feign本身提供的注解QeK28资讯网——每日最新资讯28at.com

测试代码QeK28资讯网——每日最新资讯28at.com

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参数值QeK28资讯网——每日最新资讯28at.com

Client在我们不设置的时候,就用默认的实现Client.DefaultQeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

断点打到execute方法的实现,运行,走起QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

结果就是我们设置的5sQeK28资讯网——每日最新资讯28at.com

2、在接口方法参数设置

除了在通过Feign.Builder时设置之外,Feign还支持在接口的方法参数上设置QeK28资讯网——每日最新资讯28at.com

此时你只需要在接口的方法上加一个Options类型的参数QeK28资讯网——每日最新资讯28at.com

@RequestLine("GET /user/{userId}")User queryUser(@Param("userId") Integer userId, Request.Options options);

这样在传参数时就可以设置超时时间了QeK28资讯网——每日最新资讯28at.com

User user = client.queryUser(123, new Request.Options(3, TimeUnit.SECONDS, 3, TimeUnit.SECONDS, true));

同样地,debug就可以看见我们设置的3s了QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

这两种设置超时时间的主要区别就是方法参数设置超时时间的优先级高于Feign.Builder设置的超时时间QeK28资讯网——每日最新资讯28at.com

用一张图来总结一下上面的关系QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

所以,如果你单独使用Feign的时候,你就可以通过如上的两种方式来设置超时时间。QeK28资讯网——每日最新资讯28at.com

SpringCloud下Feign单独使用超时时间设置

在SpringCloud环境下,只是对Feign进行了一层包装,所以即使没有Ribbon和注册中心,Feign也是可以单独使用的,但是用法有点变化QeK28资讯网——每日最新资讯28at.com

  • 注解都换成SpringMVC的注解
  • 接口上需要加@FeignClient注解
  • 用@EnableFeignClients扫描这些接口

不过,默认情况下Feign还是需要结合Ribbon来使用的QeK28资讯网——每日最新资讯28at.com

如果你只想单独使用Feign,那么就设置一下@FeignClient注解的url属性,指定请求的地址和端口就可以了QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

所以,既然只是包装,前面提到的两种方式设置超时时间当然可以继续使用:QeK28资讯网——每日最新资讯28at.com

  • 通过Feign.Builder
  • 通过接口的方法参数

方法参数设置形式跟前面提到的一模一样,但是通过Feign.Builder来设置却不太一样QeK28资讯网——每日最新资讯28at.com

由于SpringCloud会自己创建Feign.Builder,不需要我们创建,所以在设置Options时,Spring提供了两种快捷方式来设置QeK28资讯网——每日最新资讯28at.com

不过最终还是设置到Feign.Builder中QeK28资讯网——每日最新资讯28at.com

1、声明一个Options Bean

Spring在构建Feign.Builder的时,会从容器中查找Options这个Bean,然后设置到Feign.Builder中QeK28资讯网——每日最新资讯28at.com

@Configurationpublic class FeignConfiguration {    @Bean    public Request.Options options() {        return new Request.Options(8, TimeUnit.SECONDS, 8, TimeUnit.SECONDS, true);    }}

此时debug就可以看到设置到Feign.Builder的代码QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

这段代码在FeignClientFactoryBean中的configureUsingConfiguration方法中QeK28资讯网——每日最新资讯28at.com

2、配置文件中设置

除了声明Bean之外,Spring还提供了通过配置文件的方式配置,如下:QeK28资讯网——每日最新资讯28at.com

feign:  client:    config:      default:        connectTimeout: 10000        readTimeout: 10000

同样地,debug就可以看见QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

这段代码在FeignClientFactoryBean中的configureUsingConfiguration方法中QeK28资讯网——每日最新资讯28at.com

声明Bean和配置文件都可以设置,那么同时设置哪种优先级高呢?QeK28资讯网——每日最新资讯28at.com

如无特殊配置,遵守SpringBoot本身的配置规定QeK28资讯网——每日最新资讯28at.com

约定 > 配置 > 编码QeK28资讯网——每日最新资讯28at.com

所以基于这个规定,配置文件的配置优先级大于手动声明Bean的优先级。QeK28资讯网——每日最新资讯28at.com

到这,我们又学到了两种Spring为了方便我们设置Feign.Builder提供的配置方式:QeK28资讯网——每日最新资讯28at.com

  • 声明Options Bean
  • 配置文件

把他们俩加到前面画的图中QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

所以,如果你使用了SpringCloud提供的方式来使用Feign,那么就可以通过声明OptionsBean和配置文件的方式更加方便地来设置超时时间QeK28资讯网——每日最新资讯28at.com

最终其实还是通过Feign.Builder来设置的QeK28资讯网——每日最新资讯28at.com

SpringCloud下通过Ribbon来设置

当Feign配合Ribbon使用时,除了上面两种方式之外,还可以通过Ribbon来设置超时时间。QeK28资讯网——每日最新资讯28at.com

但是这里我不知道你会不会好奇QeK28资讯网——每日最新资讯28at.com

Ribbon不是负载均衡组件,怎么可以设置超时时间?QeK28资讯网——每日最新资讯28at.com

其实这跟Ribbon的定位有关,除了负载均衡组件之外,Ribbon也干发送Http请求的事,也就是不配合Feign,他照样可以发送http请求。QeK28资讯网——每日最新资讯28at.com

来个简单demoQeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

解释一下上面的代码意思QeK28资讯网——每日最新资讯28at.com

  • 第一步,设置user服务的两个服务实例地址
  • 第二步,获取user服务对应的RestClient,这RestClient就可以用来发送http请求
  • 第三步,构建一个http请求
  • 第四步,就是发送http请求,以负载均衡的方式

这样,此时就会从两个服务实例中根据负载均衡选取一个服务地址发送http请求,QeK28资讯网——每日最新资讯28at.com

Ribbon既然可以发送Http请求,那么自然而然就可以设置超时时间QeK28资讯网——每日最新资讯28at.com

Feign在整合Ribbon的时候,为了统一配置,就默认将自己的超时时间交由Ribbon管理QeK28资讯网——每日最新资讯28at.com

所以,在默认情况下,Feign的超时时间可以由Ribbon配置QeK28资讯网——每日最新资讯28at.com

而Ribbon默认连接和读超时时间只有1s,所以在默认情况下,Feign的超时时间只有1s。QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

IClientConfig是Ribbon的配置类,Ribbon所有的配置都可以从IClientConfig中获取。QeK28资讯网——每日最新资讯28at.com

所以,在默认情况下,很容易就发生超时,不过我们可以通过配置文件修改即可QeK28资讯网——每日最新资讯28at.com

ribbon:  ConnectTimeout: 5000  ReadTimeout: 5000

你知道你发现没,上面说通过Ribbon设置Feign的超时时间,一直提到前面一直提到这个词QeK28资讯网——每日最新资讯28at.com

默认QeK28资讯网——每日最新资讯28at.com

什么情况下叫默认呢?QeK28资讯网——每日最新资讯28at.com

所谓的默认,就是当你不主动设置Feign的超时时间的时候,就是默认。QeK28资讯网——每日最新资讯28at.com

换句话说,一旦你通过上面说的那些配置方式设置Feign的超时时间,就不是默认了QeK28资讯网——每日最新资讯28at.com

此时通过Ribbon设置的超时时间就不会生效了QeK28资讯网——每日最新资讯28at.com

Feign是如何在默认情况下将超时时间交给Ribbon管理的?

要想回答这个问题,就得先搬出前面反复提到的Client接口了。QeK28资讯网——每日最新资讯28at.com

在SpringCloud的环境下,有一个Client的实现,叫LoadBalancerFeignClientQeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

通过名字就可以看出,带有负载均衡的Client实现,负载均衡的实现肯定是交给Ribbon来实现的QeK28资讯网——每日最新资讯28at.com

所以当Feign配合Ribbon时用的就是这个Client实现QeK28资讯网——每日最新资讯28at.com

既然实现了Client接口,那就看看execute方法的实现逻辑QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

图中getClientConfig方法就是判断使用Feign或者Ribbon配置的核心逻辑QeK28资讯网——每日最新资讯28at.com

核心的判断逻辑就是这一行QeK28资讯网——每日最新资讯28at.com

options == DEFAULT_OPTIONSQeK28资讯网——每日最新资讯28at.com

DEFAULT_OPTIONS就是一个超时时间的常量QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

当上述判断条件成立时,就会通过this.clientFactory.getClientConfig(clientName)获取到Ribbon配置QeK28资讯网——每日最新资讯28at.com

由于这是Ribbon的逻辑,这里就不深扒了,知道是这个意思就行QeK28资讯网——每日最新资讯28at.com

当条件不成立时,用Options构建一个FeignOptionsClientConfigQeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

FeignOptionsClientConfig就是简单地将Options配置读出来,设置到父类DefaultClientConfigImpl超时时间配置上QeK28资讯网——每日最新资讯28at.com

DefaultClientConfigImpl就算你不知道是什么也无所谓,你能看出的一件事就是,超时时间用的是传递给Client的Options参数QeK28资讯网——每日最新资讯28at.com

所以,综上,我们的问题就变得非常easy了,那就是什么时候QeK28资讯网——每日最新资讯28at.com

options == DEFAULT_OPTIONSQeK28资讯网——每日最新资讯28at.com

只有当这个条件成立时,才使用Ribbon的配置。QeK28资讯网——每日最新资讯28at.com

这里我们先来捋一捋前面提到的东西QeK28资讯网——每日最新资讯28at.com

前面我们反复提到,Client的Options最终只来自于两种配置QeK28资讯网——每日最新资讯28at.com

  • Feign.Builder
  • 方法参数

所以DEFAULT_OPTIONS这个Options一定是通过上面两种方法中的其中一种设置的QeK28资讯网——每日最新资讯28at.com

而方法参数是不可能设置的成DEFAULT_OPTIONSQeK28资讯网——每日最新资讯28at.com

因为这是我们控制的,只要我们参数不传DEFAULT_OPTIONS,那么永远都不可能是DEFAULT_OPTIONS。QeK28资讯网——每日最新资讯28at.com

此时只剩下一种情况,那就是Spring在构建在Feign.Builder的时候,设置成DEFAULT_OPTIONS。QeK28资讯网——每日最新资讯28at.com

通过查找DEFAULT_OPTIONS的使用,我们可以追踪到这么一段代码QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

这不就是前面提到的通过声明Bean的方式来设置超时时间QeK28资讯网——每日最新资讯28at.com

不同的是它加了@ConditionalOnMissingBean,这个注解就是说,一旦我们自己没有声明Options,就用他这个OptionsQeK28资讯网——每日最新资讯28at.com

到这终于真像大白了。QeK28资讯网——每日最新资讯28at.com

我们不设置超时时间,Spring就会给Feign.Builder加一个DEFAULT_OPTIONS这个OptionsQeK28资讯网——每日最新资讯28at.com

在执行的时候,发现是DEFAULT_OPTIONS,说明我们没有主动设置过超是时间,就会使用Ribbon的超时时间。QeK28资讯网——每日最新资讯28at.com

为了方便理清上面的逻辑,这里整一张图QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

虽然Feign可以使用Ribbon的超时时间,但是Ribbon的配置的优先级是最最低的QeK28资讯网——每日最新资讯28at.com

方法参数 > Feign配置文件 > 声明Options > Ribbon配置QeK28资讯网——每日最新资讯28at.com

Feign or Ribbon配置用哪个好?

其实我个人更倾向于使用Ribbon的配置方式。QeK28资讯网——每日最新资讯28at.com

因为Ribbon除了可以设置超时时间之外,还可以配置重试机制、负载均衡等其它的配置QeK28资讯网——每日最新资讯28at.com

为了简化和统一管理配置,使用Ribbon来配置超时时间。QeK28资讯网——每日最新资讯28at.com

可能你会有疑问,Feign也支持重试机制,为什么不选择Feign?QeK28资讯网——每日最新资讯28at.com

这是因为Feign重试机制没有Ribbon的好QeK28资讯网——每日最新资讯28at.com

Ribbon重试的时候会换一个服务实例来重试,因为原来出错的可能不可用QeK28资讯网——每日最新资讯28at.com

而Feign并不会换一个服务实例重试,他并不知道上一次使用的是哪个服务实例,这就导致可能会出现在一个不可用的服务实例上多次重试的情况。QeK28资讯网——每日最新资讯28at.com

引入Hystrix时超时时间设置

如果你之前的确没有研究过关于Feign超时时间的配置关系,那么此时你应该有所收获了。QeK28资讯网——每日最新资讯28at.com

但是这就结束了么?QeK28资讯网——每日最新资讯28at.com

不,事情没那么简单。QeK28资讯网——每日最新资讯28at.com

如果你的项目中使用了Hystrix,那么就得小心前面说的那些配置了。QeK28资讯网——每日最新资讯28at.com

由于Hystrix跟Feign毕竟是一家人,所以当引入Hystrix时,Feign就跟之前不一样了。QeK28资讯网——每日最新资讯28at.com

Hystrix会去干一件事,那就是给每个Feign的http接口保护起来,毕竟Hystrix就是干保镖这个事的。QeK28资讯网——每日最新资讯28at.com

但是这没保护还好,一保护问题就不自觉地出现了。QeK28资讯网——每日最新资讯28at.com

Hystrix在保护的时候,一旦发现被保护的接口执行的时间超过Hystrix设置的最大时间,就直接进行降级操作。QeK28资讯网——每日最新资讯28at.com

怎么降级的,这里咱不关心,咱关心的是这个Hystrix超时的最大值是多少。QeK28资讯网——每日最新资讯28at.com

因为一旦这个时间小于Feign的超时时间,那么就会出现Http接口正在执行,也没有异常,仅仅是因为执行时间长,就被降级了。QeK28资讯网——每日最新资讯28at.com

而Hystrix的默认的超时时间的最大值就只有1s。QeK28资讯网——每日最新资讯28at.com

图片图片QeK28资讯网——每日最新资讯28at.com

所以就算你Feign超时时间设置的再大,超过1s就算超时,然后被降级,太坑了。。QeK28资讯网——每日最新资讯28at.com

所以我们需要修改这个默认的超时时间的最大值,具体的配置项如下QeK28资讯网——每日最新资讯28at.com

hystrix:  command:    default:      execution:        isolation:          thread:            timeoutInMilliseconds: 30000

并且时间上大致要符合下面这个原则QeK28资讯网——每日最新资讯28at.com

Hystrix超时时间 >= (连接超时时间 + 读超时时间) * 重试次数QeK28资讯网——每日最新资讯28at.com

重试次数我们前面也提到了,虽然一般我们不设置,但是为了严谨还是得加上,因为一次Http接口的执行时间肯定跟重试次数有关,重试次数越多,时间就越长。QeK28资讯网——每日最新资讯28at.com

而连接超时时间 + 读超时时间设置方式,前面提到很多次,不论是通过Feign本身设置还是通过Ribbon来设置,都是可以的QeK28资讯网——每日最新资讯28at.com

总结

今天给大家扒了扒在不同使用条件下Feign的超时时间设置,总结起来大致如下:QeK28资讯网——每日最新资讯28at.com

  • 单独使用Feign时:通过Feign.Builder和方法参数
  • SpringCloud环境下单独使用Feign:方法参数、配置文件、声明Options Bean
  • 跟Ribbon配合使用:通过Ribbon的超时参数设置
  • 跟Hystrix配合使用:修改默认的超时时间,尽量符合 Hystrix超时时间 >= (连接超时时间 + 读超时时间) * 重试次数

本文链接:http://www.28at.com/showinfo-26-5697-0.htmlFeign如何设置超时时间,不同情况下还真不一样

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 阿里云2024财年Q1 经调整EBITA利润3.87亿元

下一篇: CSS 如何改变网格布局偶数行的排序?

标签:
  • 热门焦点
Top