Skip to content
Go back

如何在 Feign 客户端中配置超时时间和重试机制?

Published:  at  12:08 PM

在微服务架构中,网络抖动或服务短暂不可用是常态。合理配置 Feign 的超时和重试,是保证系统高可用的关键。(注:以下基于当前主流的 Spring Cloud 版本,即使用 Spring Cloud LoadBalancer 替代 Ribbon 的版本)。


一、 配置超时时间(Timeout)

在 OpenFeign 中,超时时间分为两种:

  1. connectTimeout:建立 TCP 连接的超时时间。
  2. 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等操作重试

三、 最佳实践

  1. 超时时间的优先级:
    • 如果同时配置了 Feign 和 LoadBalancer(或 Ribbon)的超时,Feign 的超时时间必须大于负载均衡的超时时间,否则负载均衡的重试机制将形同虚设(因为 Feign 已经报超时异常了)。
  2. 幂等性警告:
    • 在配置重试时,一定要强调接口幂等性。对于非幂等操作(如扣款、创建订单),严禁盲目开启重试,或者必须配合全局唯一 ID(如 Token、雪花算法 ID)在服务端做去重处理。
  3. 熔断与重试的配合:
    • 重试次数不宜过多(通常 1-2 次),否则会引发“重试风暴”,导致下游服务雪崩。建议结合 Sentinel 或 Resilience4j 做熔断降级,当错误率达到阈值时直接快速失败。

Suggest Changes

Previous Post
Spring MVC 自定义参数解析:按类型注入请求上下文
Next Post
Feign 是如何工作的?它的核心注解有哪些?