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

简介: 该文章详细分析了OpenFeign与Ribbon之间的超时配置关系,解释了Ribbon如何覆盖OpenFeign的默认超时配置,并探讨了OpenFeign超时配置的动态修改方案。

前言

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

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

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

OpenFeign配置超时方式

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

   public static class Options {
   
   
        //连接超时时间
        private final int connectTimeoutMillis;
        //读数据超时时间
        private final int readTimeoutMillis;
        private final boolean followRedirects;
   }

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

 public Options() {
   
   
            this(10000, 60000);
        }

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

  • 全局配置方式一

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

  • 全局配置方式二
@Configuration
public class TestFeignClientConfiguration {
   
   

    @Bean
    public Request.Options options() {
   
   
        //配置全局300ms就超时
        Request.Options options = new Request.Options(300, 300);
        return new Request.Options();
    }
}
}
  • 指定FeignClient生效配置一 以feignClientFeignClientApi为例 feign.client.config.FeignClientApi.connectTimeout=1000 feign.client.config.FeignClientApi.readTimeout=1000

  • 指定FeignClient生效配置二

@FeignClient(value = "fox-server", contextId = "feignClientApi", configuration = TestFeignClientConfiguration.class)
public interface FeignClientApi {
   
   
        @PostMapping("/get")
        String getName(@RequestBody @Validated DemoRequest request);
}

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

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

配置生效原理

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

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

@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({
   
    FeignClientProperties.class,
        FeignHttpClientProperties.class })
public class FeignAutoConfiguration {
   
   
}

配置类以feign.client开头

@ConfigurationProperties("feign.client")
public class FeignClientProperties {
   
   

    private boolean defaultToProperties = true;

    private String defaultConfig = "default";

    private Map<String, FeignClientConfiguration> config = new HashMap<>();

FeignClientConfiguration中有超时时间字段

image.png

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

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

具体在哪使用的呢?

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

protected void configureFeign(FeignContext context, Feign.Builder builder) {
   
   
        //查找`FeignClientProperties`
        FeignClientProperties properties = this.applicationContext
                .getBean(FeignClientProperties.class);
        if (properties != null) {
   
   
            if (properties.isDefaultToProperties()) {
   
   
                configureUsingConfiguration(context, builder);
                configureUsingProperties(
                        properties.getConfig().get(properties.getDefaultConfig()),
                        builder);
                configureUsingProperties(properties.getConfig().get(this.contextId),
                        builder);
            }
            else {
   
   
                configureUsingProperties(
                        properties.getConfig().get(properties.getDefaultConfig()),
                        builder);
                configureUsingProperties(properties.getConfig().get(this.contextId),
                        builder);
                configureUsingConfiguration(context, builder);
            }
        }
        else {
   
   
            configureUsingConfiguration(context, builder);
        }
    }

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

image.png

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

protected void configureUsingProperties(
            FeignClientProperties.FeignClientConfiguration config,
            Feign.Builder builder) {
   
   

        if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
   
   
            builder.options(new Request.Options(config.getConnectTimeout(),
                    config.getReadTimeout()));
        }

    }

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

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

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

IClientConfig getClientConfig(Request.Options options, String clientName) {
   
   
        IClientConfig requestConfig;
        //默认10s的配置情况,使用ribbon配置覆盖默认配置
        if (options == DEFAULT_OPTIONS) {
   
   
            requestConfig = this.clientFactory.getClientConfig(clientName);
        }
        else {
   
   
            requestConfig = new FeignOptionsClientConfig(options);
        }
        return requestConfig;
    }

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

image.png

@Override
    public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
            throws IOException {
   
   
        Request.Options options;
        //存在配置了,读已经配置的,如果为空,使用ribbon配置
        if (configOverride != null) {
   
   
            RibbonProperties override = RibbonProperties.from(configOverride);
            options = new Request.Options(override.connectTimeout(this.connectTimeout),
                    override.readTimeout(this.readTimeout));
        }
        else {
   
   
            options = new Request.Options(this.connectTimeout, this.readTimeout);
        }
        Response response = request.client().execute(request.toRequest(), options);
        return new RibbonResponse(request.getUri(), response);
    }

OpenFeign超时配置问题

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

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

image.png

总结

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

相关文章
|
3月前
|
存储 设计模式 缓存
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
该文章主要介绍了如何在OpenFeign中集成Ribbon以实现负载均衡,并详细分析了Ribbon中服务选择和服务过滤的核心实现过程。文章还涉及了Ribbon中负载均衡器(ILoadBalancer)和负载均衡策略(IRule)的初始化方式。
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
|
3月前
|
缓存 负载均衡 Java
OpenFeign最核心组件LoadBalancerFeignClient详解(集成Ribbon负载均衡能力)
文章标题为“OpenFeign的Ribbon负载均衡详解”,是继OpenFeign十大可扩展组件讨论之后,深入探讨了Ribbon如何为OpenFeign提供负载均衡能力的详解。
OpenFeign最核心组件LoadBalancerFeignClient详解(集成Ribbon负载均衡能力)
|
4月前
|
监控 Cloud Native Java
通用快照方案问题之Hystrix和Ribbon在超时设置上的冲突如何解决
通用快照方案问题之Hystrix和Ribbon在超时设置上的冲突如何解决
50 0
|
6月前
|
负载均衡 Java 应用服务中间件
Ribbon、Feign和OpenFeign的区别来了
Ribbon、Feign和OpenFeign的区别来了
275 2
|
6月前
Springcloud-ribbon和hystrix配置
Springcloud-ribbon和hystrix配置
43 0
Ribbon、Feign、Hystrix超时&重试&熔断问题
在使用Ribbon、Feign、Hystrix组合时,因为配置的问题出现以下现象,让我的大脑CPU烧的不行不行(拿我老家话说就是“脑子ran滴奥”)
181 0
|
6月前
|
负载均衡 Java 应用服务中间件
springcloud3-服务到服务调用ribbon及openfeign
springcloud3-服务到服务调用ribbon及openfeign
78 0
|
11月前
|
负载均衡 Java 数据库连接
原来Nacos、OpenFeign、Ribbon、loadbalancer组件是这么协调工作的
大家好,我是三友~~ 前几天有个大兄弟问了我一个问题,注册中心要集成SpringCloud,想实现SpringCloud的负载均衡,需要实现哪些接口和规范。
原来Nacos、OpenFeign、Ribbon、loadbalancer组件是这么协调工作的
|
6月前
|
Java 微服务 Spring
Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用
Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用
99 0
|
存储 负载均衡 算法
扒一扒Nacos、OpenFeign、Ribbon、loadbalancer组件协调工作原理
前几天有个大兄弟问了我一个问题,注册中心要集成SpringCloud,想实现SpringCloud的负载均衡,需要实现哪些接口和规范。