高并发feign调用 :Address already in use: no further information executing POST
问题描述
最近再测试数据时,发现高并发情况下,服务之间的feign调用会出现一下报错:
Address already in use: no further information executing POST
原因
查找了一些资料,也做了一些测试,最终确认可能时因为并发量太大,HTTP连接未及时释放。导致资源耗尽了。
Feign默认使用的是HTTP客户端,比如JDK自带的HttpURLConnection,但它的性能可能不够好,特别是在高并发下容易耗尽连接池资源。通常的解决方法是替换为更高效的客户端,例如Apache HttpClient或OkHttp,并配置连接池参数。
解决办法
使用Apache HttpClient
依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>12.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
先自定义实现相关配置
@Configuration
public class FeignConfig {@Bean@Primary //确保全局配置类中的Bean名称不与自动配置冲突public CloseableHttpClient httpClient() {return HttpClientBuilder.create()// 设置最大连接总数.setMaxConnTotal(200)// 设置单个路由的最大连接数(针对特定目标主机的最大并发).setMaxConnPerRoute(50)// 配置连接存活时间(单位:毫秒).setKeepAliveStrategy((response, context) -> 30000)// 禁用自动重试.disableAutomaticRetries().build();}@Bean@Primary //确保全局配置类中的Bean名称不与自动配置冲突public Client feignClient() {return new ApacheHttpClient(httpClient());}// 可选:配置超时参数@Bean@Primary //确保全局配置类中的Bean名称不与自动配置冲突public Request.Options options() {return new Request.Options(5_000, // 连接超时时间(ms)10_000 // 读取超时时间(ms));}
}
再具体的feign中配置:
@FeignClient(name = "serviceName",configuration = FeignConfig.class // 指定配置类)
public interface MyFeignClient {// ...
}
如果时全局的feign都使用这个配置,在@EnableFeignClients注解有一个defaultConfiguration属性,可以指定一个全局的配置类,这样所有Feign客户端都会应用这个配置,而无需每个客户端单独指定。
// 全局配置方案:通过@EnableFeignClients注解统一指定
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = FeignConfig.class) // 关键配置
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
若某个Feign客户端单独指定了configuration
,则局部配置优先于全局配置
使用okHttp
// OkHttp全局配置方案
@Configuration
public class FeignOkHttpConfig {// 配置OkHttp连接池(默认最大空闲连接数5,存活时间5分钟)@Beanpublic OkHttpClient okHttpClient() {return new OkHttpClient.Builder().connectionPool(new ConnectionPool(100, // 最大空闲连接数5, // 存活时间(单位:分钟)TimeUnit.MINUTES)).connectTimeout(5, TimeUnit.SECONDS) // 连接超时.readTimeout(10, TimeUnit.SECONDS) // 读取超时.writeTimeout(10, TimeUnit.SECONDS) // 写入超时.retryOnConnectionFailure(false) // 禁用自动重试.build();}// 声明使用OkHttp客户端@Beanpublic Client feignClient(OkHttpClient okHttpClient) {return new feign.okhttp.OkHttpClient(okHttpClient);}
}
全局配置和单一的feign配置和httpclient一样
@EnableFeignClients(defaultConfiguration = FeignOkHttpConfig.class)
@SpringBootApplication(exclude = {HttpClientAutoConfiguration.class // 排除Apache HttpClient自动配置
})
public class Application {...}