> 文档中心 > Java HttpClient 连接池复用分析

Java HttpClient 连接池复用分析

Java HttpClient 连接池复用分析

    • 场景描述
    • 问题描述
    • 日志分析
    • 代码分析
    • 解决

在Java 11中,HttpClient被添加进去。支持Http/1.1 和Http/2,并分别支持同步和异步调用两种方法。
上周使用HttpClient, 对一个后端服务进行压测,遇到了一些问题。

场景描述

场景比较简单,就是开200个线程,对后端服务接口进行压测,服务接口调用使用Java HttpClient。
在这里插入图片描述

问题描述

从后端服务监控看,RPS远不及预期,从LB的监控看,有数4000+的并发连接。这和实际的情况不符啊。
我开了200个线程,HttpClient的调用采用同步方式调用,按道理使用连接池,应该是200个并发链接才对,这里面一定有问题。
在这里插入图片描述

日志分析

先看下客户端日志吧,有大量的日志如下,
在这里插入图片描述

应该是创建的连接过多,创建新的tcp连接失败,再使用netstat 看下tcp连接的情况,
在这里插入图片描述
很快就达到16000多个连接。这说明连接池肯定没有复用。

有两种可能,一种是用完的连接没有回收到连接池,一种是请求的时候没有从连接池中获取到可复用的连接。

代码分析

单步调试下,在
HttpConnection::getConnection()中,

   if (!secure) { c = pool.getConnection(false, addr, proxy); if (c != null && c.checkOpen() /* may have been eof/closed when in the pool */) {     final HttpConnection conn = c;     if (DEBUG_LOGGER.on())  DEBUG_LOGGER.log(conn.getConnectionFlow()     + ": plain connection retrieved from HTTP/1.1 pool");     return c; } else {     return getPlainConnection(addr, proxy, request, client); }    } else {  // secure if (version != HTTP_2) { // only HTTP/1.1 connections are in the pool     c = pool.getConnection(true, addr, proxy); } if (c != null && c.isOpen()) {     final HttpConnection conn = c;     if (DEBUG_LOGGER.on())  DEBUG_LOGGER.log(conn.getConnectionFlow()     + ": SSL connection retrieved from HTTP/1.1 pool");     return c; } else {     String[] alpn = null;     if (version == HTTP_2 && hasRequiredHTTP2TLSVersion(client)) {  alpn = new String[] { "h2", "http/1.1" };     }     return getSSLConnection(addr, proxy, alpn, request, client); // 跑到这了 }    }

跑到了最后,协议走的是http/2。 协议如果走的http/2的话,没有从连接池中获取可复用连接。

解决

那么,显示的指定下http协议版本1.1。
重新跑下,
在这里插入图片描述
可以看到连接数变成了200个,也不再报错了,并发请求量也提升了。