HttpClient 学习笔记【原创】
程序员文章站
2022-06-13 19:41:36
...
HttpClient 某些方法的作用梳理。本文的测试基于httpcore-4.3.3.jar,httpclient-4.3.6.jar.
创建一个httpClient, 使用默认连接池。当多个线程使用同一个httpClient, 如果不调用httpClient.close(); 则多个线程共享两个连接。通过后台发现,始终有一个连接处于established状态。官网文章中说(默认,每个路由基础上的连接不超过2个,总连接数不能超过20)
关闭客户端,这时候如果有链接处于established状态,则装为TIME_WAIT状态。
httpClient创建的时候指定连接池,总连接数为200,每个域连接数最大为20。用多线程跑一下,发现一个站点最大连接数正好为20。
调用httpPost.abort(); 之后,连接被关闭,处于TIME_WAIT状态。这样做两个好处,一是当判断到状态码不为200的时候,不继续读取response内容,提升性能。二是这个连接可能有问题,关闭节省资源。多线程调用,故意使一个请求返回之后调用httpPost.abort()效果如下:
虽然httpClient是线程安全的,但是官网仍建议每个线程创建使用自己的上下文。
官网示例代码是写response.close(); 但是好像写不写效果一样的,待翻源码。
连接池需要自行清除过期和失效连接。
将tomcat服务器连接超时时间改为5秒后,过了5秒,客户端的连接都变成CLOSE_WAIT状态。
这时调用httpClient.close();方法就能正常关闭端口连接。测试还发现设置keepAliveTimeOut没有发生作用。
tomcat服务器设置这个之后,长连接失效,httpClient.execute(httppost)调用完即处于close_wait状态,等待EntityUtils.toString(entity, "UTF-8");之后,连接即可关闭。
当开启长连接,并设置connectionTimeout为5秒,connMgr.closeIdleConnections(30, TimeUnit.SECONDS);程序清除30秒内不活动连接。这时访问,发现5秒后后连接状态由established改为close_wait, 再过30秒后连接被清除。
设置客户端自定义的超时策略对链接超时并没有影响,还是以tomcat服务端的connectionTimeOut时长为准。以上代码虽然设置了客户端5秒超时,但实际是到30s之后才把链接状态由ESTABLISHED改为CLOSE_WAIT。 这30s正是服务端的connectionTimeOut时间。
问题一:
最近线上httpClient调用老是报 xxx.xxx.xxx.xxx:xxxx failed to respond
网上说有两种情况:
1)被调用的服务器过载,导致没有挥手即断开连接,客户端下一次请求时重用了这个已经失效的连接,就会报这个错误。
2)并发太高,服务器在挥手的过程中,客户端重用了连接,给的解决方案是发现这个错误,重新建一个连接(不从连接池取),这样保证连接是正常的,重新调用一次,调用完关闭。
我查看了业务服务,发现压力并不是很大。因此判断是不是服务器主动发起了关闭连接,而客户端仍然将这个连接保持在连接池中。因为客户端连接池的策略是每5s检测并关闭30s内不活跃的连接。tomcat服务器keepAliveTimeout默认是15s. 也就是说当连接空闲的15s-30s之间业务重用了这个连接,就会发生这个错误。
因此,修改tomcat的这个参数之后,一切正常。
CloseableHttpClient httpClient =HttpClients.createDefault();
创建一个httpClient, 使用默认连接池。当多个线程使用同一个httpClient, 如果不调用httpClient.close(); 则多个线程共享两个连接。通过后台发现,始终有一个连接处于established状态。官网文章中说(默认,每个路由基础上的连接不超过2个,总连接数不能超过20)
httpClient.close();
关闭客户端,这时候如果有链接处于established状态,则装为TIME_WAIT状态。
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); // 将最大连接数增加到200 cm.setMaxTotal(maxTotal); // 将每个路由基础的连接增加到20 cm.setDefaultMaxPerRoute(defaultMaxPerRoute); // 设置超时时间 RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();//设置请求和传输超时时间 // 创建默认的httpClient实例. CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).build();
httpClient创建的时候指定连接池,总连接数为200,每个域连接数最大为20。用多线程跑一下,发现一个站点最大连接数正好为20。
if (response.getStatusLine().getStatusCode()!= HttpStatus.SC_OK) { httpPost.abort(); return null; }
调用httpPost.abort(); 之后,连接被关闭,处于TIME_WAIT状态。这样做两个好处,一是当判断到状态码不为200的时候,不继续读取response内容,提升性能。二是这个连接可能有问题,关闭节省资源。多线程调用,故意使一个请求返回之后调用httpPost.abort()效果如下:
HttpContext context = HttpClientContext.create(); CloseableHttpResponse response = httpClient.execute(httpPost, context);
虽然httpClient是线程安全的,但是官网仍建议每个线程创建使用自己的上下文。
response.close(); httpPost.releaseConnection();
官网示例代码是写response.close(); 但是好像写不写效果一样的,待翻源码。
// 关闭失效的连接 connMgr.closeExpiredConnections(); // 可选的, 关闭30秒内不活动的连接 connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
连接池需要自行清除过期和失效连接。
connectionTimeout="5000"
将tomcat服务器连接超时时间改为5秒后,过了5秒,客户端的连接都变成CLOSE_WAIT状态。
这时调用httpClient.close();方法就能正常关闭端口连接。测试还发现设置keepAliveTimeOut没有发生作用。
maxKeepAliveRequests="1"
tomcat服务器设置这个之后,长连接失效,httpClient.execute(httppost)调用完即处于close_wait状态,等待EntityUtils.toString(entity, "UTF-8");之后,连接即可关闭。
当开启长连接,并设置connectionTimeout为5秒,connMgr.closeIdleConnections(30, TimeUnit.SECONDS);程序清除30秒内不活动连接。这时访问,发现5秒后后连接状态由established改为close_wait, 再过30秒后连接被清除。
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { public long getKeepAliveDuration(HttpResponse response, HttpContext context) { // Honor 'keep-alive' header HeaderElementIterator it = new BasicHeaderElementIterator( response.headerIterator(HTTP.CONN_KEEP_ALIVE)); while (it.hasNext()) { HeaderElement he = it.nextElement(); String param = he.getName(); String value = he.getValue(); if (value != null && param.equalsIgnoreCase("timeout")) { try { return Long.parseLong(value) * 1000; } catch(NumberFormatException ignore) { } } } // Keep alive for 5 seconds only return 5 * 1000; } }; PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); // 将最大连接数增加到200 cm.setMaxTotal(100); // 将每个路由基础的连接增加到20 cm.setDefaultMaxPerRoute(5); // 创建默认的httpClient实例. CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).setKeepAliveStrategy(myStrategy).build();
设置客户端自定义的超时策略对链接超时并没有影响,还是以tomcat服务端的connectionTimeOut时长为准。以上代码虽然设置了客户端5秒超时,但实际是到30s之后才把链接状态由ESTABLISHED改为CLOSE_WAIT。 这30s正是服务端的connectionTimeOut时间。
问题一:
最近线上httpClient调用老是报 xxx.xxx.xxx.xxx:xxxx failed to respond
网上说有两种情况:
1)被调用的服务器过载,导致没有挥手即断开连接,客户端下一次请求时重用了这个已经失效的连接,就会报这个错误。
2)并发太高,服务器在挥手的过程中,客户端重用了连接,给的解决方案是发现这个错误,重新建一个连接(不从连接池取),这样保证连接是正常的,重新调用一次,调用完关闭。
我查看了业务服务,发现压力并不是很大。因此判断是不是服务器主动发起了关闭连接,而客户端仍然将这个连接保持在连接池中。因为客户端连接池的策略是每5s检测并关闭30s内不活跃的连接。tomcat服务器keepAliveTimeout默认是15s. 也就是说当连接空闲的15s-30s之间业务重用了这个连接,就会发生这个错误。
因此,修改tomcat的这个参数之后,一切正常。
上一篇: PHP文本型数据库分类排序的实现
下一篇: 田忌最后是怎么死的?田忌是一个怎样的人?