feign 使用tcp连接池
feign实现
跟踪程序断点发现feign每次调用时,均通过(HttpURLConnection) new URL(request.url()).openConnection()
建立新的连接
feign使用连接池
pom配置
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
application配置
feign:
httpclient:
enabled: true
测试
启用上述配置后,此处的client使用的不再是默认client而是ApacheHttpClient
发现此处使用的是AbstractConnPool,同zuul的实现
常规压测
实现
- feign
@FeignClient(name = "baiduFeign", url = "https://www.baidu.com")
public interface BaiduFeign {
@GetMapping
String baidu();
}
- controller
@RestController
@RequestMapping("/baidu")
public class BaiduController {
@Autowired
private BaiduFeign baiduFeign;
@GetMapping
public String baidu() {
return baiduFeign.baidu();
}
}
- 分别在使用
feign-httpclient
与不使用的情况下通过wrk压测
wrk -t1 -c1 -d 1000s -H "Authorization: 0cb99a92f9ad4f998d09c515c4299a86" https://p-api-test.taoche.cn/v1/business-application/baidu
压测分析
发现使用new URL(request.url()).openConnection()
和AbstractConnPool
两种方式的请求时间结果并没有明显变化
并且发现在使用new URL(request.url()).openConnection()
方式时连接的端口一直没有变化
原因为HttpURLConnction在Connection: close
模式时使用完成后调用关闭InputStream会自动关闭连接;当使用Connection: Keep-Alive
模式时,关闭InputStream后,并不会断开底层Socket连接,当需要连接到同一服务器地址时,可以利用该Socket,这时如果要断开连接,可调用connection.disconnect()
由于当前http默认均为长连接,故使用上述两种方式均会复用tcp连接,所以接口性能无明显变化
降低调用频次
实现
- feign 同上
- controller 同上
- 分别在使用
feign-httpclient
与不使用的情况下通过以下test类压测
@Test
public void test() throws Exception {
for (int i = 0; i < 1000; i++) {
String resp = testFeign.test("34bde626faf04965b1023d334d9698fe");
System.out.println(resp);
Thread.sleep(5000);
}
}
压测分析
由于每5s执行一次代码,所以调用其它服务接口间休眠5s,故new URL(request.url()).openConnection()
模式下无法复用socket,即每次生成新的socket
发现平均时长为60ms+,比常规压测的时长40ms长了不少
调整为AbstractConnPool模式,同样的方式测试
通过上述结果可发现 此模式在一开始时耗时较高,之后性能在40ms,比上一模式性能提升50%
故 如果接口请求频繁,则两种模式均会利用socket,但是如果请求不频繁,如上述超过5s请求一次,则AbstractConnPool模式模式性能远远高于new URL(request.url()).openConnection()
的性能。
但是使用AbstractConnPool模式时,需要注意设置每个route的最大连接数,以便及时回收连接
多线程测试
实现
- feign 同上
- controller 同上
- 分别在使用
feign-httpclient
与不使用的情况下通过以下test类压测
@Test
public void test() throws Exception {
Thread t1 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
String resp = testFeign.test("34bde626faf04965b1023d334d9698fe");
System.out.println(resp);
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
String resp = testFeign.test("34bde626faf04965b1023d334d9698fe");
System.out.println(resp);
}
}
};
t1.start();
t2.start();
t1.join();
t2.join();
}
压测分析
在使用AbstractConnPool模式时,服务器为两个tcp连接
使用HttpURLConnection时,同样会复用连接
总结
feign默认是使用的new URL(request.url()).openConnection()
,该模式底层在短时间内也会复用socket连接,而feign-httpclient引入自管理的连接池,具体实现是使用的AbstractConnPool。
如果短时间的请求,则两种模式性能差别很小,如果间隔时间较长,则AbstractConnPool更优