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 也会重试,极易造成重复提交 优化方案:
- 全局关闭默认重试
@Bean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
- 自定义重试:仅允许 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,大量接口调用时负载均衡阻塞会拖性能:
- 调整 Ribbon 连接池和超时
ribbon:
ReadTimeout: 4000
ConnectTimeout: 2000
MaxTotalConnections: 300
MaxConnectionsPerHost: 80
- 开启饥饿加载,项目启动时初始化 Feign 客户端,避免首次调用慢
ribbon:
eager-load:
enabled: true
clients: service-user,service-order # 需要预热的服务名
- 优先使用 Nacos 原生负载均衡替代 Ribbon(SpringCloud Alibaba),减少一层封装开销
七、业务层编码优化
- 接口粒度拆分 禁止一次 Feign 调用拉取全量数据,拆分成分页、小接口;批量接口统一批量入参,减少循环调用 Feign(循环远程调用是性能杀手) 反例:
// 差:循环远程调用,大量网络往返
for(Long id : idList){
UserDTO user = userFeign.getById(id);
}
// 优:批量接口一次请求
List<UserDTO> list = userFeign.batchGet(idList);
- 复用 Feign 客户端实例 FeignClient 注解默认单例,不要手动 new FeignBuilder 重复创建,每个创建都会新建连接池、编解码器。
- 请求头复用、减少重复构建 统一拦截器全局注入 token、traceId,不要每个接口手动传 header。
- 异步 Feign 调用(高并发异步场景) 使用 CompletableFuture 异步调用,释放 Tomcat 线程:
@FeignClient("user-service")
public interface UserFeign {
@GetMapping("/user/{id}")
CompletableFuture<UserDTO> getUser(@PathVariable Long id);
}
八、拦截器性能优化
- 拦截器逻辑轻量化,不做复杂序列化、IO、数据库操作
- 拦截器按需注册,避免全局过多拦截器链式执行耗时
- 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
十、性能优化验收指标
优化前后对比观测:
- 接口平均 RT 下降 30%~80%
- TCP TIME_WAIT 连接数大幅降低
- 线程池无耗尽、无大量等待
- 无频繁创建销毁 HTTP 连接
- 监控无大量 Feign 重试、超时异常
优化优先级总结(按收益从高到低)
- 替换底层 HttpURLConnection → OkHttp/HttpClient(收益最大)
- 合理配置连接池参数,开启饥饿加载
- 关闭 Full 日志,线上仅 BASIC/NONE
- 序列化替换 FastJson2,精简传输 DTO
- 线程隔离(Sentinel/Hystrix),合理超时与重试
- 业务避免循环远程调用,使用批量接口
- 异步调用、轻量化拦截器