在微服务架构中,网络抖动或服务短暂不可用是常态。合理配置 Feign 的超时和重试,是保证系统高可用的关键。(注:以下基于当前主流的 Spring Cloud 版本,即使用 Spring Cloud LoadBalancer 替代 Ribbon 的版本)。
一、 配置超时时间(Timeout)
在 OpenFeign 中,超时时间分为两种:
connectTimeout:建立 TCP 连接的超时时间。readTimeout:建立连接后,读取服务端返回数据的超时时间。
1. 全局配置(application.yml)
在配置文件中设置 default 级别的配置,对所有 Feign 客户端生效:
feign:
client:
config:
default:
connectTimeout: 5000 # 连接超时 5秒
readTimeout: 5000 # 读取超时 5秒
2. 针对特定服务配置
如果某个服务响应较慢,可以单独为该服务设置更长的超时时间:
feign:
client:
config:
user-service: # 对应 @FeignClient(name = "user-service")
connectTimeout: 2000
readTimeout: 10000
3. Java Config 方式配置
也可以通过配置类的方式注入:
@Configuration
public class FeignConfig {
@Bean
public Request.Options feignOptions() {
// 连接超时 5秒,读取超时 10秒
return new Request.Options(5000, TimeUnit.MILLISECONDS, 10000, TimeUnit.MILLISECONDS, true);
}
}
(注意:如果使用 Java Config,请确保该类没有被 @ComponentScan 扫描到全局,否则会变成全局配置。通常建议放在单独的包下,通过 @FeignClient(configuration = FeignConfig.class) 指定。)
二、 配置重试机制(Retry)
在 Spring Cloud 中,重试机制分为Feign 原生重试和Spring Cloud LoadBalancer 重试。默认情况下,Spring Cloud 关闭了 Feign 的原生重试(Retryer.NEVER_RETRY),以便将重试控制权交给负载均衡器。
1. 自定义 Feign 原生重试
如果你希望使用 Feign 自带的重试策略,需要注入一个 Retryer Bean:
@Configuration
public class FeignRetryConfig {
@Bean
public Retryer feignRetryer() {
// 参数:重试间隔(ms),最大重试间隔(ms),最大重试次数
// 默认策略:初始间隔100ms,最大间隔1s,最多重试5次
return new Retryer.Default(100, 1000, 3);
}
}
注意:一旦开启 Feign 原生重试,若配合 LoadBalancer 使用,可能会导致重试次数放大(例如 Feign 重试 3 次,LoadBalancer 也重试 3 次,最终可能请求 9 次)。
2. 推荐:Spring Cloud LoadBalancer 重试(主流做法)
在 application.yml 中开启并配置 LoadBalancer 的重试机制:
spring:
cloud:
loadbalancer:
retry:
enabled: true # 开启重试
max-retries-on-same-service-instance: 0 # 同一实例最大重试次数
max-retries-on-next-service-instance: 2 # 切换到下一个实例的最大重试次数
retry-on-all-operations: true # 是否对所有操作(包括POST)重试
注意:retry-on-all-operations: true 非常危险! 默认情况下,LoadBalancer 只对 GET 请求重试。如果对 POST 请求重试,必须保证接口是幂等的(例如使用唯一请求号防重),否则会造成数据重复写入。
3. 历史版本(Ribbon)的重试配置
如果你使用的是老版本 Spring Cloud(基于 Netflix Ribbon),配置如下(作为知识扩展):
user-service:
ribbon:
MaxAutoRetries: 1 # 同一实例重试次数
MaxAutoRetriesNextServer: 2 # 切换实例重试次数
OkToRetryOnAllOperations: false # 是否对POST等操作重试
三、 最佳实践
- 超时时间的优先级:
- 如果同时配置了 Feign 和 LoadBalancer(或 Ribbon)的超时,Feign 的超时时间必须大于负载均衡的超时时间,否则负载均衡的重试机制将形同虚设(因为 Feign 已经报超时异常了)。
- 幂等性警告:
- 在配置重试时,一定要强调接口幂等性。对于非幂等操作(如扣款、创建订单),严禁盲目开启重试,或者必须配合全局唯一 ID(如 Token、雪花算法 ID)在服务端做去重处理。
- 熔断与重试的配合:
- 重试次数不宜过多(通常 1-2 次),否则会引发“重试风暴”,导致下游服务雪崩。建议结合 Sentinel 或 Resilience4j 做熔断降级,当错误率达到阈值时直接快速失败。