可以做分析图的地图网站,万网的怎么做网站地图,行业信息网站,网站域名备案代理1. 引言
在spring cloud微服中#xff0c;feign远程调用可能是大家每天都接触到东西#xff0c;但很多同学却没咋搞清楚这里边的各种超时问题#xff0c;生产环境可能会蹦出各种奇怪的问题。 首先说下结论#xff1a; 1)只使用feign组件#xff0c;不使用ribbion组件feign远程调用可能是大家每天都接触到东西但很多同学却没咋搞清楚这里边的各种超时问题生产环境可能会蹦出各种奇怪的问题。 首先说下结论 1)只使用feign组件不使用ribbion组件其默认feign的连接超时是10s,读超时是60s; 2) 同时使用了feign和ribbion组件(1)若没有任何人为配置超时时间远程调用使用ribbion的默认超时时间连接超时、读超时都是1秒钟(2)若同时主动配置了feign 、ribbion的超时时间则使用配置的feign超时时间(3)若只主动配置了feign的超时时间则使用配置的feign超时时间(4)若只主动配置了ribbon超时时间则使用配置的ribbion超时时间。
2. only feign
feign本身是通过FeignClientFactoryBean 创建出来的,feign的超时配置也在方法org.springframework.cloud.openfeign.FeignClientFactoryBean#configureUsingConfiguration中。此方法properties.isDefaultToProperties()的默认值是true,我们一般也不会去改它所以一般是执行红方框中的逻辑。(1)先执行全局配置configureUsingConfiguration(context, builder)(2)再执行属性配置类中FeignClientProperties的默认配置, (3)最后执行属性配置类FeignClientProperties中当前feign client特定的配置。这三个步骤的覆盖顺序是后者覆盖前者也就是越往后优先级越高。默认情况下我们未做任何配置时FeignClientProperties是空对象也就是说此时只会执行步骤(1)的属性配置。 全局属性配置方法org.springframework.cloud.openfeign.FeignClientFactoryBean#configureUsingConfiguration回到spring容器中去取超时配置对象Request.Options 自动配置类相应方法为我们配置了一个Request.Options对象(当spring容器中不存在此类型的bean时) 而LoadBalancerFeignClient.DEFAULT_OPTIONS的连接超时、读超时分别是10s、60s. public class LoadBalancerFeignClient implements Client {static final Request.Options DEFAULT_OPTIONS new Request.Options();//.....
} public static class Options {private final long connectTimeout;private final TimeUnit connectTimeoutUnit;private final long readTimeout;private final TimeUnit readTimeoutUnit;private final boolean followRedirects;//......./*** Creates the new Options instance using the following defaults:* ul* liConnect Timeout: 10 seconds/li* liRead Timeout: 60 seconds/li* liFollow all 3xx redirects/li* /ul*/public Options() {this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);}//.......} 3. feignribbon
在feign引入ribbon负载均衡时远程调用的feign client会用LoadBalancerFeignClient. 在LoadBalancerFeignClient方法中有调用getClientConfig(options, clientName);的代码行而IClientConfig中包含有feign和ribbion超时时间。 getClientConfig方法参数中的options是feign本身的超时配置 可以看到当参数options等于DEFAULT_OPTIONS,即没有为feign主动配置超时时间这种情况这种情况会到容器用去获取超时配置当options不等于DEFAULT_OPTIONS即已经为feign主动配置了超时时间这种情况下我们会使用feign的超时时间。
IClientConfig getClientConfig(Request.Options options, String clientName) {IClientConfig requestConfig;if (options DEFAULT_OPTIONS) {requestConfig this.clientFactory.getClientConfig(clientName);}else {requestConfig new FeignOptionsClientConfig(options);}return requestConfig;}这个IClientConfig 在配置类org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration的配置方法ribbonClientConfig执行config.loadProperties(this.name);将配置文件中ribbion的配置信息赋值到config对象后又执行了config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT); 、 config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);重新将连接超时、读超时重置为1000毫秒即1秒。
SuppressWarnings(deprecation)
Configuration(proxyBeanMethods false)
EnableConfigurationProperties
// Order is important here, last should be the default, first should be optional
// see
// https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
Import({ HttpClientConfiguration.class, OkHttpRibbonConfiguration.class,RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class })
public class RibbonClientConfiguration {/*** Ribbon client default connect timeout.*/public static final int DEFAULT_CONNECT_TIMEOUT 1000;/*** Ribbon client default read timeout.*/public static final int DEFAULT_READ_TIMEOUT 1000;/*** Ribbon client default Gzip Payload flag.*/public static final boolean DEFAULT_GZIP_PAYLOAD true;RibbonClientNameprivate String name client;
BeanConditionalOnMissingBeanpublic IClientConfig ribbonClientConfig() {DefaultClientConfigImpl config new DefaultClientConfigImpl();config.loadProperties(this.name);config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);return config;}//....}}我们在看看DefaultClientConfigImpl的怎么处理属性的。 可以看出上边RibbonClientConfiguration.ribbonClientConfig方法中设置的超时时间它们被放在DefaultClientConfigImpl#properties中的而取配置属性的底层方法都是getProperty(String key)所以在没有为feign配置超时时间时ribbon的取值时先取当前指定ribbon client的超时时间若不存在则取全局ribbon的超时时间若还是不存在则取DefaultClientConfigImpl#properties中的默认值1秒。
public class DefaultClientConfigImpl implements IClientConfig {Overridepublic T DefaultClientConfigImpl set(IClientConfigKeyT key, T value) {properties.put(key.key(), value);return this;}protected Object getProperty(String key) {//这里enableDynamicProperties一定是trueif (enableDynamicProperties) {String dynamicValue null;DynamicStringProperty dynamicProperty dynamicProperties.get(key);//dynamicProperty是nullif (dynamicProperty ! null) {dynamicValue dynamicProperty.get();}if (dynamicValue null) {//到配置文件中取当前client的clientName.ribbion.ReadTimeout这种格式的属性dynamicValue DynamicProperty.getInstance(getConfigKey(key)).getString();if (dynamicValue null) {//到配置文件中取全局ribbion.ReadTimeout这种格式的属性dynamicValue DynamicProperty.getInstance(getDefaultPropName(key)).getString();}}if (dynamicValue ! null) {return dynamicValue;}}//DefaultClientConfigImpl类中定义的默认值return properties.get(key);}}LoadBalancerFeignClient#execute 方法中的lbClient(clientName)创建了一个负载均衡器RetryableFeignLoadBalancer且此负载均衡期中的config就是上边RibbonClientConfiguration#ribbonClientConfig配置方法中所对应的IClientConfig.
private FeignLoadBalancer lbClient(String clientName) {return this.lbClientFactory.create(clientName);}
public FeignLoadBalancer create(String clientName) {FeignLoadBalancer client this.cache.get(clientName);if (client ! null) {return client;}IClientConfig config this.factory.getClientConfig(clientName);ILoadBalancer lb this.factory.getLoadBalancer(clientName);ServerIntrospector serverIntrospector this.factory.getInstance(clientName,ServerIntrospector.class);client this.loadBalancedRetryFactory ! null? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,this.loadBalancedRetryFactory): new FeignLoadBalancer(lb, config, serverIntrospector);this.cache.put(clientName, client);return client;}现在回到LoadBalancerFeignClient#execute方法块调用负载均衡的 return lbClient(clientName) .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();的核心实现RetryableFeignLoadBalancer#execute FeignLoadBalancer是RetryableFeignLoadBalancer的父类型构造RetryableFeignLoadBalancer时调用的构造方法new RetryableFeignLoadBalancer(lb, config, serverIntrospector, this.loadBalancedRetryFactory)会调用父类的public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) 方法而RibbonClientConfiguration#ribbonClientConfig配置方法中所对应的IClientConfig会传入此构造方法的clientConfig参数因此这里的this.connectTimeout this.readTimeout都是ribbon的超时时间。 configOverride是feign超时配置或ribbon超时配置而ribbon.connectTimeout(this.connectTimeout)中this.connectTime超时参数是作为默认值的所以说ribbon超时参数是会被覆盖掉它的优先级低(feign、ribbon超时参数同时存在时)