Ribbon的超时配置会覆盖OpenFeign的超时配置吗

蔚落 2023-10-13 17:10 62阅读 0赞

前言

平常的开发工作中调用Rpc服务最关注的性能指标就是响应时间rt,OpenFeign提供了超时时间配置项。本文将从源码层面分析OpenFeign超时时间配置原理,以及Ribbon超时配置的关系分析。

通过本文可以明白两个问题:

  • OpenFeign超时配置和Ribbon超时配置的关系
  • OpenFeign超时配置能否动态实时修改生效

OpenFeign配置超时方式

在OpenFeign中,有一个超时项配置类,专门用来接收超时配置的。 支持连接超时和读数据超时配置,所有的超时配置最终都会生成对应的Options实例。

  1. java复制代码 public static class Options {
  2. //连接超时时间
  3. private final int connectTimeoutMillis;
  4. //读数据超时时间
  5. private final int readTimeoutMillis;
  6. private final boolean followRedirects;
  7. }

默认多久超时呢? 在FeignRibbonClientAutoConfiguration自动配置中使用了默认的构造函数,根据构造函数参数,默认连接超时10s,读数据6s超时,也就是不改配置,OpenFeign的接口默认超时时间有10s。

  1. java复制代码 public Options() {
  2. this(10000, 60000);
  3. }

OpenFeign到底有哪些配置方式呢?

  • 全局配置方式一

feign.client.config.default.connectTimeout=1000 feign.client.config.default.readTimeout=1000

  • 全局配置方式二

    java复制代码@Configuration
    public class TestFeignClientConfiguration {

    1. @Bean
    2. public Request.Options options() {
    3. //配置全局300ms就超时
    4. Request.Options options = new Request.Options(300, 300);
    5. return new Request.Options();
    6. }

    }
    }

  • 指定FeignClient生效配置一 以feignClientFeignClientApi为例 feign.client.config.FeignClientApi.connectTimeout=1000 feign.client.config.FeignClientApi.readTimeout=1000

  • 指定FeignClient生效配置二

    java复制代码@FeignClient(value = “fox-server”, contextId = “feignClientApi”, configuration = TestFeignClientConfiguration.class)
    public interface FeignClientApi {

    1. @PostMapping("/get")
    2. String getName(@RequestBody @Validated DemoRequest request);

    }

    //和全局配置比少了Configuration注解
    public class TestFeignClientConfiguration {

    1. @Bean
    2. public Request.Options options() {
    3. //配置全局300ms就超时
    4. Request.Options options = new Request.Options(300, 300);
    5. return new Request.Options();
    6. }

    }
    }

配置生效原理

这些配置是怎么生效的呢?

首先在Feign的自动装配类FeignAutoConfiguration中,启用了 FeignClientProperties配置类。这样配置文件里的属性就可以被解析了。

  1. java复制代码@Configuration
  2. @ConditionalOnClass(Feign.class)
  3. @EnableConfigurationProperties({ FeignClientProperties.class,
  4. FeignHttpClientProperties.class })
  5. public class FeignAutoConfiguration {
  6. }

配置类以feign.client开头

  1. java复制代码@ConfigurationProperties("feign.client")
  2. public class FeignClientProperties {
  3. private boolean defaultToProperties = true;
  4. private String defaultConfig = "default";
  5. private Map<String, FeignClientConfiguration> config = new HashMap<>();

在FeignClientConfiguration中有超时时间字段

image.png

get_code_MGUyNzIwMzY5Y2QzOGFiOWU4M2NjMDg0ZDAxOTVlYWYsMTY4OTMwMDM3NTcyMQ

这样Spring容器启动后会将feign.client为前缀的配置项注入到FeignClientProperties类对象中。

由于配置项config是一个map,只要key是对应的FeignClient里的contextId或者default就会生效。

具体在哪使用的呢?

在Feign初始化阶段,从Spring容器读取FeignClientProperties

  1. java复制代码protected void configureFeign(FeignContext context, Feign.Builder builder) {
  2. //查找`FeignClientProperties`
  3. FeignClientProperties properties = this.applicationContext
  4. .getBean(FeignClientProperties.class);
  5. if (properties != null) {
  6. if (properties.isDefaultToProperties()) {
  7. configureUsingConfiguration(context, builder);
  8. configureUsingProperties(
  9. properties.getConfig().get(properties.getDefaultConfig()),
  10. builder);
  11. configureUsingProperties(properties.getConfig().get(this.contextId),
  12. builder);
  13. }
  14. else {
  15. configureUsingProperties(
  16. properties.getConfig().get(properties.getDefaultConfig()),
  17. builder);
  18. configureUsingProperties(properties.getConfig().get(this.contextId),
  19. builder);
  20. configureUsingConfiguration(context, builder);
  21. }
  22. }
  23. else {
  24. configureUsingConfiguration(context, builder);
  25. }
  26. }

上面的代码就涉及到了配置优先级问题。默认是配置文件里的优先。

image.png

get_code_YzdiN2FkNjFjNzk1ZmI5YTQxY2Q3OWJkNTRkOWMxNjIsMTY4OTMwMDM3NTcyMQ

根据优先级确定配置后,构造Request.Options对象,与FeignClient对象绑定。

  1. java复制代码protected void configureUsingProperties(
  2. FeignClientProperties.FeignClientConfiguration config,
  3. Feign.Builder builder) {
  4. if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
  5. builder.options(new Request.Options(config.getConnectTimeout(),
  6. config.getReadTimeout()));
  7. }
  8. }

上面是初始化好了Feign的超时配置,如果使用了ribbon负载均衡,在执行阶段可能会被修改。

  • 如果是OpenFeign默认配置,使用ribbon配置覆盖默认配置

org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient#getClientConfig

  1. java复制代码IClientConfig getClientConfig(Request.Options options, String clientName) {
  2. IClientConfig requestConfig;
  3. //默认10s的配置情况,使用ribbon配置覆盖默认配置
  4. if (options == DEFAULT_OPTIONS) {
  5. requestConfig = this.clientFactory.getClientConfig(clientName);
  6. }
  7. else {
  8. requestConfig = new FeignOptionsClientConfig(options);
  9. }
  10. return requestConfig;
  11. }

执行请求前,如果有配置优先使用已有的配置,兜底使用ribbon配置。整体流程如下

image.png

get_code_ZjFjZjlkYjhkNDE3OTliYjBlNmY0ODg1YTA5YTIyYjMsMTY4OTMwMDM3NTcyMQ

  1. java复制代码@Override
  2. public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
  3. throws IOException {
  4. Request.Options options;
  5. //存在配置了,读已经配置的,如果为空,使用ribbon配置
  6. if (configOverride != null) {
  7. RibbonProperties override = RibbonProperties.from(configOverride);
  8. options = new Request.Options(override.connectTimeout(this.connectTimeout),
  9. override.readTimeout(this.readTimeout));
  10. }
  11. else {
  12. options = new Request.Options(this.connectTimeout, this.readTimeout);
  13. }
  14. Response response = request.client().execute(request.toRequest(), options);
  15. return new RibbonResponse(request.getUri(), response);
  16. }

OpenFeign超时配置问题

配置都是生成FeignClient对象之前就设置好了,如果想动态实时生效是不支持的,修改超时时间需要重启服务。有没有办法不重启服务实时生效呢?

我们可以写一个aop切面,拦截feign.Client#execute方法,第二个参数就是调用时候会使用的Options参数,只要修改第二个参数就可以了。

image.png

get_code_ZTgwZGJlMDg1MWQ5NjcyYmZkZDRiYzQ4NzAyYWNhNjAsMTY4OTMwMDM3NTcyMQ

总结

1、OpenFeign支持配置类和配置文件配置超时时间,默认连接超时时间是10s,读数据时间6s,配置文件的优先生效 2、Ribbon支持配置超时时间,默认1s,如果OpenFeign没有单独配置超时时间,则会使用Ribbon的超时时间覆盖 3、OpenFeign超时时间是构造Client之前就初始化好了,不支持动态修改生效,可以通过aop拦截Client的execute方法修改。

发表评论

表情:
评论列表 (有 0 条评论,62人围观)

还没有评论,来说两句吧...

相关阅读

    相关 OpenFeign超时控制

    OpenFeign超时控制 超时设置,故意设置超时演示出错情况 什么是超时控制 YML文件里开启OpenFeign客户端超时控制 为了方便只演示