- 顶: 2踩: 15
Feign
自身有超时时间配置Feign
默认集成的Ribbon
中也有超时时间配置假如我们又使用了
Hystrix
来实现熔断降级,Hystrix
自身也有一个超时时间配置
注:
spring-cloud-starter-openfeign
低一点的版本中默认集成的有Hystrix
,高版本中又移除了。一、Feign和 Ribbon
1. 设置 OpenFeign 的超时时间
我们首先来看一下
OpenFeign
自己的请求超时配置,直接在 yml 文件中配置:feign: # 设置 feign 超时时间 client: config: # default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间 default: connectTimeout: 5000 readTimeout: 5000
default 默认是全局的,将 default 换成某个服务的名称可以设置单个服务的超时时间
2. 设置 Ribbon 的超时时间
ribbon: # 建立链接所用的时间,适用于网络状况正常的情况下, 两端链接所用的时间 ReadTimeout: 5000 # 指的是建立链接后从服务器读取可用资源所用的时间 ConectTimeout: 5000
注意这两个参数设置的时候没有智能提示!
ConnectTimeout:
指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。在java中,网络状况正常的情况下,例如使用 HttpClient 或者 HttpURLConnetion 连接时设置参数 connectTimeout=5000 即5秒,如果连接用时超过5秒就是抛出 java.net.SocketException: connetct time out 的异常。
ReadTimeout:
指的是建立连接后从服务器读取到可用资源所用的时间。在这里我们可以这样理解ReadTimeout:正常情况下,当我们发出请求时可以收到请求的结果,也就是页面上展示的内容,但是当网络状况很差的时候,就会出现页面上无法展示出内容的情况。另外当我们使用爬虫或者其他全自动的程序时,无法判断当前的网络状况是否良好,此时就有了ReadTimeout的用武之地了,通过设置ReadTimeout参数,例:ReadTimeout=5000,超过5秒没有读取到内容时,就认为此次读取不到内容并抛出Java.net.SocketException: read time out的异常。
3. 源码追踪
配置都比较简单,接下来我们来追踪一下相关的源码。
首先从
@EnableFeignClients
进去,再到FeignClientsRegistrar
类中跟踪到
FeignClientsRegistrar
类中的registerFeignClient
方法接着到
FeignClientFactoryBean
类中的configureUsingProperties
方法最后一直跟到
feign.Request
中的这里可以发现
OpenFeign
的默认的connectTimeout
是 10 秒,readTimeout
是 60 秒。接下来我们来验证一下,修改我们测试用的那个接口,让它睡个 5 秒
@GetMapping("/getUserInfo")public Map<String, Object> getUserInfo(int userId){ Map<String, Object> map = new HashMap<String, Object>(); User user = new User(1, "小黑", 26); map.put("code", 200); map.put("data", user.toString()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return map;}
OpenFeign
默认超时时间
此时,我们是要验证
OpenFeign
的默认超时时间,所以在application.yml
中 feign 和 ribbon 的超时时间都没有设置。启动项目再次调用我们的老接口:
http://localhost:9203/test/getUserInfo?userId=2
疑问? 报错了,连接超时,可是我们代码里睡 5 秒,明明还在超时时间范围内,怎么就连接超时了呐?
其实
OpenFeign
集成了Ribbon
,Ribbon 的默认超时连接时间、读超时时间都是 1 秒,源码在org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer#execute()
方法中,如下图:断点打到这里(需要访问上面接口才会进断点)会发现:如果
OpenFeign
没有设置对应得超时时间,那么将会采用Ribbon
的默认超时时间设置
OpenFeign
超时时间
feign:client: config: default: connectTimeout: 8000 readTimeout: 8000
然后我们重启项目后再访问接口进入上面那个断点看看,发现超时时间变成我们配置的了
接口也返回了正常的结果:
设置
Ribbon
超时时间
ribbon: ReadTimeout: 7000 ConectTimeout: 7000
重复上面步骤,断点进去一看 ???怎么还是 8000
原因是 ,
OpenFeign
和Ribbon
的超时时间只会有一个生效两者是二选一的,且OpenFeign
优先。并且,注掉OpenFeign
超时时间配置之后,就变成了使用设置的Ribbon
的超时时间,更加验证了OpenFeign
优先。4. 结论
Feign
和Ribbon
的超时时间只会有一个生效,规则:如果没有设置过feign超时(也就是等于默认值的时候),就会读取 ribbon 的配置,使用 ribbon 的超时时间和重试设置。
如果设置了feign超时,则使用 feign 自身的设置。两者是二选一的,且 feign 优先。
二、Ribbon 和 Hystrix
1. Hystrix 设置超时时间
# 先要开启feign.hystrix.enabled,然后下面这个配置才会起作用feign: hystrix: enabled: truehystrix: command: default: execution: timeout: enabled: true isolation: thread: timeoutInMilliseconds: 5000
配置好 fallback
@FeignClient(contextId = "remoteUserService", value = "cloud-system", fallbackFactory = RemoteUserFallbackFactory.class)
注意:如果没有配置 fallback,那么 hystrix 的超时就不会生效,而是由 ribbon 来控制。
hystrix 的默认超时时间是 1s,这个配置在 HystrixCommandProperties 类中:
private static final Integer default_executionTimeoutInMilliseconds = 1000;
设置 hystrix 超时时间比 ribbon 大(OpenFign 的超时时间注掉)
ribbon: ReadTimeout: 2000 ConectTimeout: 2000
访问地址
http://localhost:9203/test/getUserInfo?userId=2
发现请求 2s 左右就返回了,这个值刚好是 ribbon.ReadTimeout 的时间。表示此时 ribbon 超时触发了。然后进入了 hystrix 的熔断过程。2. 结论:
如果请求时间超过 ribbon 的超时配置,会触发重试;
在配置 fallback 的情况下,如果请求的时间(包括 ribbon 的重试时间),超出了 ribbon 的超时限制,或者 hystrix 的超时限制,那么就会熔断。
一般来说,会设置 ribbon 的超时时间 < hystrix, 这是因为 ribbon 有重试机制。(这里说的 ribbon 超时时间是包括重试在内的,即,最好要让 ribbon 的重试全部执行,直到 ribbon 超时被触发)。
由于 connectionTime 一般比较短,可以忽略。那么,设置的超时时间应该满足如下,避免ribbon还未重试完就过早的被Hystrix熔断了:
(1 + MaxAutoRetries) * (1 + MaxAutoRetriesNextServer)* ReadTimeOut < hystrix 的 *timeoutInMilliseconds
附录1:
一、 Feign设置超时时间
使用Feign调用接口分两层,ribbon的调用和hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间
#hystrix的超时时间hystrix: command: default: execution: timeout: enabled: true isolation: thread: timeoutInMilliseconds: 9000#ribbon的超时时间ribbon: ReadTimeout: 60000 ConnectTimeout: 60000
一般情况下 都是 ribbon 的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制)因为ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,源码如下
要开启Feign的重试机制如下:(Feign默认重试五次 源码中有)
@BeanRetryer feignRetryer() { return new Retryer.Default();}
二、ribbon的重试机制
设置重试次数:
ribbon: ReadTimeout: 3000 ConnectTimeout: 3000 MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用 MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用 OkToRetryOnAllOperations: false #是否所有操作都重试
根据上面的参数计算重试的次数:MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries *MaxAutoRetriesNextServer) 即重试3次 则一共产生4次调用如果在重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,fallback。所以要根据上面配置的参数计算hystrix的超时时间,使得在重试期间不能达到hystrix的超时时间,不然重试机制就会没有意义。hystrix超时时间的计算:(1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout 即按照以上的配置 hystrix的超时时间应该配置为 (1+1+1)*3=9秒
当ribbon超时后且hystrix没有超时,便会采取重试机制。当OkToRetryOnAllOperations设置为false时,只会对get请求进行重试。如果设置为true,便会对所有的请求进行重试,如果是put或post等写操作,如果服务器接口没做幂等性,会产生不好的结果,所以OkToRetryOnAllOperations慎用。
如果不配置ribbon的重试次数,默认会重试一次注意:默认情况下,GET方式请求无论是连接异常还是读取异常,都会进行重试非GET方式请求,只有连接异常时,才会进行重试
附录2 spring cloud ribbon配置自动重试
spring cloud 通过eureka 访问其他服务默认没有重试机制,需要额外进行配置实现客户端重试,特别是对方服务在进行滚动发布的时候,本地维护的节点信息还没有更新,就需要进行自动重试,保证前端业务流畅。
pom文件添加依赖:
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency>
应用添加配置:
ribbon.ReadTimeout=30000ribbon.ConnectTimeout=5000ribbon.SocketTimeout=30000ribbon.MaxAutoRetries=0ribbon.MaxAutoRetriesNextServer=2ribbon.OkToRetryOnAllOperations=trueribbon.ServerListRefreshInterval=5000spring.cloud.loadbalancer.retry.enable=true
客户端使用可以直接根据服务名进行访问了:服务内注入restTemplate进行外部服务访问:
BaseResponse response = restTemplate.postForObject("http://xxx-service/cellphone", req, new BaseResponse<String>().getClass());
4 补充实现AbstractLoadBalancingClient的类有
4.1 RetryableOkHttpLoadBalancingClient(spring-retry)开启条件
# 导入spring-retry 依赖ribbon.okhttp.enabled=trueribbon.httpclient.enabled=false
4.2 OkHttpLoadBalancingClient开启条件
ribbon.okhttp.enabled=trueribbon.httpclient.enabled=false
4.3 RibbonLoadBalancingHttpClient开启条件默认
4.4 RetryableRibbonLoadBalancingHttpClient(spring-try)开启条件
spring.cloud.loadbalancer.retry.enabled=truezuul.retryable=true#导入spring-try#Retry 次数计算#reTry次数的计算= (MaxAutoRetries*+1)*(MaxAutoRetriesNextServer+1)
超时最大时间
ribbonTimeout=(ribbonReadTimeout+ ribbonConnectTimeout) *(maxAutoRetries + 1) * (maxAutoRetriesNextServer+ 1)
gateway:
- name: Retryargs:retries: 1methods: GET,POST#多个参数用-连接statuses: BAD_GATEWAY#参考同上,series与statuses二选一即可series: #表示5xx,以5开头的各种状态码- SERVER_ERROR exceptions: #有以下异常时触发重试,此处注意timeout的时间与熔断设置的时间 - java.util.concurrent.TimeoutException - java.net.ConnectException
get io异常 重试;post io异常 不重试;
ribbon resttemplate:
spring.cloud.loadbalancer.retry.enabled=trueribbon.ConnectTimeout=1000ribbon.ReadTimeout=10000ribbon.OkToRetryOnAllOperations=falseribbon.MaxAutoRetriesNextServer=2ribbon.maxAutoRetries=0
get 在发生io异常的时候回进行重试;post 在发生io异常不会进行重试;开启Hystrix
同样的,Feign中已经内置了Hystrix,直接通过配置来开启Hystrix,如下所示:
feign: hsytrix: enabled: true
开启Feign功能
在服务消费方的引导类上添加注解@EnableFeignClients,用于开启Feign功能。
优化Feign第一次调用的策略
Feign初始化开销
懒加载(Lazy Loading):Feign客户端通常是在需要时才进行初始化的,这种机制被称为懒加载。当第一次调用Feign客户端时,它会执行一系列的初始化操作,包括加载配置、创建代理对象、解析服务地址、建立连接池等。这些操作都需要一定的时间来完成,因此第一次调用自然会相对较慢。
服务发现和注册:如果你的应用使用了服务注册与发现机制(如Eureka、Consul等),Feign在第一次调用时还需要从注册中心获取服务的实例信息。这个过程涉及到网络通信和DNS解析,可能会因为网络延迟或注册中心的性能问题而变慢。
线程池和连接池初始化:Feign在进行远程调用时,通常会使用线程池来管理线程,以及连接池来管理HTTP连接。第一次调用时,这些资源可能还没有初始化好,Feign需要创建新的线程和连接,这也会增加调用的启动时间。
类加载和代理生成:Feign使用动态代理来生成客户端代码,第一次调用时可能需要加载和生成相关的类,这同样会增加调用的启动时间。Ribbon饥饿加载:开启Ribbon的饥饿加载模式,让Ribbon在应用启动时就完成服务列表的加载和缓存,避免在第一次调用时进行这些操作。配置方式如下:
ribbon: eager-load: enabled: true clients: your-feign-client-name # 注解 @FeignClient 中的 value 值写在此处
Feign配置压缩
Spring Cloud Feign能够对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。直接通过配置feign中的参数即可开启压缩功能,如下所示:
feign: compression: request: enabled: true #请求压缩 mime-types: text/html,application/xml,application.json #压缩的数据类型 mim-request-size: 2048 #设置触发压缩的大小下限 response: enabled: true #响应压缩
Feign支持的日志级别:
(1) NONE: 不记录任何日志信息,默认(2) BASIC: 只记录请求的方法,URL以及响应状态码和执行时间
(3) HEADERS:在BASIC的基础上,添加了请求和响应的头信息
(4) FULL:记录所有请求和响应的明细,包括头信息,请求体,元数据
(1)开启Feign日志配置文件写法:
开启Feign的日志功能,可以帮助你更清晰地了解Feign在调用过程中的行为,包括初始化过程、请求发送、响应接收等。这有助于你定位问题并进行优化。配置方式如下:feign: client: config: default: loggerLevel: full logging: level: com.yourpackage.feignclient: debug
(2)开启Feign日志的配置类写法:
添加Feign的配置类,定义日志级别。注意,要在该配置类上添加@Configuration表示这是一个配置类。
package com.springboot.config;import feign.Logger;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; }}
Feign Hystrix 熔断、线程使用坑点:
hystrx 官方配置解释地址:
https://github.com/Netflix/Hystrix/wiki/Configuration
线程池队列配置问题
常用配置:
#核心线程池大小,默认值为:10 hystrix.threadpool.default.coreSize=10 #调用超时时间,默认值为1000ms hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=15000 #最大线程池大小,这是在不开始拒绝的情况下可以支持的最大并发量。默认值为10。 hystrix.threadpool.default.maximumSize=50 #队列大小拒绝阈值,默认值为5。即使maxQueueSize未达到也会发生拒绝。在maxQueueSize==-1时不生效。 hystrix.threadpool.default.queueSizeRejectionThreshold=100 #maximumSize配置是否生效,默认值为false。maximumSize可以等于或高于coreSize。 #设置coreSize< maximumSize 创建一个可以维持maximumSize并发性的线程池; # 但会在相对不活动期间将线程返回给系统。(受限于keepAliveTimeInMinutes)。 hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize = true # 最大队列大小,默认值为 -1。# 值为-1时:使用 thenSynchronousQueue;# 值为正值时:使用 LinkedBlockingQueue。 hystrix.threadpool.default.maxQueueSize = 50
错误配置①:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000
feign使用的是懒加载,第一次调用时,会初始化各种bean,速度很慢,默认1秒很容易超时。
错误配置②:
hystrix.threadpool.default.coreSize=10hystrix.threadpool.default.maxQueueSize=1000hystrix.threadpool.default.queueSizeRejectionThreshold=20
因为 queueSizeRejectionThreshold 太小,实际上在并发达到 30 以上的时候,就会拒绝后面的请求了。
错误配置③:
hystrix.threadpool.default.coreSize=10hystrix.threadpool.default.maxQueueSize=20hystrix.threadpool.default.queueSizeRejectionThreshold=1000
因为 maxQueueSize 太小,实际上在并发达到 30 以上的时候,就会拒绝后面的请求了。
微服务系列:Spring Cloud 之 Feign、Ribbon、Hystrix 三者超时时间配置
人参与 | 时间:2025-06-24 13:09:47
相关文章
- Redispipeline(管道)详解
- 专家表示,今年的汽车价格战将极其激烈 头部竞争格局尚未稳定
- 技术骑士:128GB内存 酷睿i7强芯 4060显卡电子竞技办公室适合2098元起享受性价比高的游戏主机
- 用特斯拉的钱买飞行摩托车,谁还买飞行车?
- 王祖贤开车上班的照片曝光 14年前驾驶白色保时捷卡宴
- 【手写数据库核心组件】0104双向循环链表,麻雀虽小,但需要精心设计,整体分层抽象,遍历多种形式
- 比亚迪仰望 U7 预热:100公里/h 高速行驶被侧向追尾,仍能稳步行驶
- SQLCipher:SQLite加密工具的实用指南
- 苹果地图为福特车主更新电动汽车路线规划,支持特斯拉超充电站导航
- REDMI Turbo 4钢铁侠定制版亮相:全套深度定制配件,包装
评论专区