Feign服务性能优化

0 阅读5分钟

Feign 是 SpringCloud 声明式 HTTP 客户端,默认封装 RestTemplate,存在序列化、连接池、拦截器、日志、超时、负载均衡等多层性能瓶颈,下面分底层通信替换、连接池、序列化、超时重试、日志、负载均衡、业务代码七大维度完整优化。

一、底层通信替换(最大性能提升点)

默认 Feign 使用 HttpURLConnection,无连接池、每次创建销毁连接、性能极差,必须替换为带连接池的实现。

方案 1:Apache HttpClient(推荐稳定)

1. 引入依赖

<!-- feign httpclient 支持 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

2. 开启 HttpClient + 连接池配置

feign:
  httpclient:
    enabled: true # 启用httpclient
    max-connections: 200 # 全局最大连接数
    max-connections-per-route: 50 # 单个服务最大连接
    follow-redirects: false

方案 2:OkHttp(高并发场景性能更强)

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>
feign:
  okhttp:
    enabled: true

关键结论

  • HttpURLConnection:无池,并发高会大量 TIME_WAIT,必弃用
  • OkHttp:异步、多路复用、连接复用更好,高并发首选
  • Apache HttpClient:兼容性强,老项目迁移稳妥

二、连接池精细化调参(核心优化)

核心参数说明

表格

参数作用建议值
max-connections整个应用全局连接上限200~500
max-connections-per-route单个目标服务连接上限50~100
connection-timeout连接建立超时2000ms
read-timeout接口读取超时5000ms
keep-alive 时长空闲连接存活30s~60s

自定义连接池配置(Java 代码)

@Bean
public CloseableHttpClient httpClient() {
    Registry<ConnectionSocketFactory> registry = RegistryBuilder.create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", SSLConnectionSocketFactory.getSocketFactory())
            .build();
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
    connectionManager.setMaxTotal(300);
    connectionManager.setDefaultMaxPerRoute(80);
    // 空闲连接清理
    connectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
    return HttpClients.custom()
            .setConnectionManager(connectionManager)
            .evictIdleConnections(30, TimeUnit.SECONDS)
            .build();
}

三、序列化优化(减少编解码耗时)

Feign 默认使用 feign.codec.DefaultDecoder + Jackson,存在反射开销,优化方向:

1. 替换为 FastJson2 / Gson

FastJson2 示例

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-fastjson2</artifactId>
</dependency>
@Bean
public FeignDecoder feignDecoder() {
    return new FastJson2Decoder();
}
@Bean
public FeignEncoder feignEncoder() {
    return new FastJson2Encoder();
}

优势:序列化速度远快于原生 Jackson,大数据包提升明显。

2. 关闭 Jackson 自动格式化、禁用无用特性

ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.INDENT_OUTPUT); // 不格式化输出
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, false);

3. 避免传输大对象、分页查询

大 JSON 序列化 / 网络传输耗时极高,统一分页、精简 DTO 字段。

四、超时、重试、熔断优化(避免雪崩拖慢性能)

1. 合理设置超时(区分连接 / 读取超时)

feign:
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 4000

禁止超时设置过大:接口阻塞会占用连接池,耗尽线程。

2. 重试策略优化(Feign 内置 Retryer)

默认重试:GET 请求失败自动重试 3 次,POST 也会重试,极易造成重复提交 优化方案:

  1. 全局关闭默认重试
@Bean
public Retryer feignRetryer() {
    return Retryer.NEVER_RETRY;
}
  1. 自定义重试:仅允许 GET / 查询接口重试,写接口禁止重试
public class CustomRetryer implements Retryer {
    @Override
    public void continueOrPropagate(RetryableException e) {
        // 判断请求方法,POST直接抛异常不重试
        if (e.request().method().equals("POST")) {
            throw e;
        }
    }
    @Override
    public Retryer clone() {
        return new CustomRetryer();
    }
}

3. 整合 Sentinel/Hystrix 隔离(线程池隔离,防止服务雪崩)

以 Sentinel 为例:

feign:
  sentinel:
    enabled: true
spring:
  cloud:
    sentinel:
      feign:
        default-rule:
          thread-count: 20 # 单个Feign客户端线程池大小

隔离优势:某个下游服务慢不会占满整个应用 Tomcat 线程。

五、日志优化(线上严禁 Full 日志,严重损耗性能)

Feign 日志级别 4 档:

  • NONE:无日志(线上推荐)
  • BASIC:仅记录请求方法、URL、响应码、耗时
  • HEADERS:基础 + 请求头响应头
  • FULL:请求体、响应体全打印,序列化 + IO 开销极大,生产禁用

配置

feign:
  client:
    config:
      default:
        loggerLevel: BASIC # 生产环境最低仅保留BASIC

开发环境可开 FULL,线上必须切 BASIC/NONE。

六、负载均衡优化(Ribbon/Nacos 负载均衡)

SpringCloud Feign 默认整合 Ribbon,大量接口调用时负载均衡阻塞会拖性能:

  1. 调整 Ribbon 连接池和超时
ribbon:
  ReadTimeout: 4000
  ConnectTimeout: 2000
  MaxTotalConnections: 300
  MaxConnectionsPerHost: 80
  1. 开启饥饿加载,项目启动时初始化 Feign 客户端,避免首次调用慢
ribbon:
  eager-load:
    enabled: true
    clients: service-user,service-order # 需要预热的服务名
  1. 优先使用 Nacos 原生负载均衡替代 Ribbon(SpringCloud Alibaba),减少一层封装开销

七、业务层编码优化

  1. 接口粒度拆分 禁止一次 Feign 调用拉取全量数据,拆分成分页、小接口;批量接口统一批量入参,减少循环调用 Feign(循环远程调用是性能杀手) 反例:
// 差:循环远程调用,大量网络往返
for(Long id : idList){
    UserDTO user = userFeign.getById(id);
}
// 优:批量接口一次请求
List<UserDTO> list = userFeign.batchGet(idList);
  1. 复用 Feign 客户端实例 FeignClient 注解默认单例,不要手动 new FeignBuilder 重复创建,每个创建都会新建连接池、编解码器。
  2. 请求头复用、减少重复构建 统一拦截器全局注入 token、traceId,不要每个接口手动传 header。
  3. 异步 Feign 调用(高并发异步场景) 使用 CompletableFuture 异步调用,释放 Tomcat 线程:
@FeignClient("user-service")
public interface UserFeign {
    @GetMapping("/user/{id}")
    CompletableFuture<UserDTO> getUser(@PathVariable Long id);
}

八、拦截器性能优化

  1. 拦截器逻辑轻量化,不做复杂序列化、IO、数据库操作
  2. 拦截器按需注册,避免全局过多拦截器链式执行耗时
  3. Trace 链路工具(SkyWalking/Pinpoint)过滤 Feign 大量日志采集,减少埋点开销

九、完整最优配置模板(OkHttp + 连接池 + Sentinel)

feign:
  okhttp:
    enabled: true
  sentinel:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 4000
        loggerLevel: BASIC
ribbon:
  eager-load:
    enabled: true
  MaxTotalConnections: 300
  MaxConnectionsPerHost: 80

十、性能优化验收指标

优化前后对比观测:

  1. 接口平均 RT 下降 30%~80%
  2. TCP TIME_WAIT 连接数大幅降低
  3. 线程池无耗尽、无大量等待
  4. 无频繁创建销毁 HTTP 连接
  5. 监控无大量 Feign 重试、超时异常

优化优先级总结(按收益从高到低)

  1. 替换底层 HttpURLConnection → OkHttp/HttpClient(收益最大)
  2. 合理配置连接池参数,开启饥饿加载
  3. 关闭 Full 日志,线上仅 BASIC/NONE
  4. 序列化替换 FastJson2,精简传输 DTO
  5. 线程隔离(Sentinel/Hystrix),合理超时与重试
  6. 业务避免循环远程调用,使用批量接口
  7. 异步调用、轻量化拦截器