httpclient 连接池测试

为什么需要使用http连接池

1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗,别小看这几次握手,本人经过测试发现,基本上3倍的时间延迟

2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接

连接池实例

连接池管理器代码

import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;
import java.security.NoSuchAlgorithmException;

public class HttpConnectionManager {

    PoolingHttpClientConnectionManager cm = null;

    @PostConstruct
    public void init() {
        LayeredConnectionSocketFactory sslsf = null;
        try {
            sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("https", sslsf)
                .register("http", new PlainConnectionSocketFactory())
                .build();
        cm =new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        cm.setMaxTotal(200);
        cm.setDefaultMaxPerRoute(20);
    }

    public CloseableHttpClient getHttpClient() {
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(cm)
                .build();

        /*CloseableHttpClient httpClient = HttpClients.createDefault();//如果不采用连接池就是这种方式获取连接*/
        return httpClient;
    }
}

使用连接池代码

private static CloseableHttpClient getHttpClient(){
        HttpConnectionManager httpConnectionManager= (HttpConnectionManager) AppBeanUtil.getBean("httpConnectionManager");
        return  httpConnectionManager.getHttpClient();
    }

获取连接

public static String getFromUrl(String url, Map<String, String> params,String charset) throws Exception {
        if(StringUtil.isEmpty(charset)){
            charset=defaultCharset;
        }
        CloseableHttpClient httpclient = getHttpClient();
        URIBuilder uriBuilder = new URIBuilder(url);
        uriBuilder.setCharset(Charset.forName(charset));
        if(params!=null){
            Iterator<String> keyIt = params.keySet().iterator();
            while (keyIt.hasNext()) {
                String key = keyIt.next();
                String val = params.get(key);
                uriBuilder.setParameter(key, val);
            }
        }
        URI uri = uriBuilder.build();

        HttpGet httpget = new HttpGet(uri);

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String content=getContent(entity.getContent());
                return content;
            }
        } finally {
            response.close();
        }
        return null;
    }

访问url 获取内容

private static String getContent(InputStream instream) throws IOException {
        StringWriter writer = new StringWriter();
        IOUtils.copy(instream, writer, defaultCharset);
        instream.close();
        return writer.toString();
    }

读取数据,这里 instream 需要进行关闭。

测试连接池和不使用连接池的效率测试。

@Test
    public void postTest() throws Exception {

        long start=System.currentTimeMillis();
        for (int i = 0; i < 200; i++) {
            String content=HttpClientPoolUtil.postFromUrl("https://www.cnblogs.com/kingszelda/p/8988505.html",new HashMap<>());
        }
        System.err.println("---------------------------postTest---------------------------");
        System.err.println(System.currentTimeMillis()-start);

        System.err.println("---------------------------postTest---------------------------");
        start=System.currentTimeMillis();
        for (int i = 0; i < 200; i++) {
            String content= HttpClientUtil.postFromUrl("https://www.cnblogs.com/kingszelda/p/8988505.html",new HashMap<>());
        }
        System.err.println(System.currentTimeMillis()-start);

    }

测试结果

---------------------------postTest---------------------------
9791
---------------------------postTest---------------------------
39427

可以看到在使用连接池访问两百次花费时间为 9.7秒,不使用连接池为 39.4秒,时间相差为30秒。

通过计算从发送请求到接收请求约花48毫秒,每建立一次连接需要花费的时间为150毫秒,可见创建连接是需要非常消耗性能的。

原文地址:https://www.cnblogs.com/yg_zhang/p/12239409.html

时间: 2024-11-06 18:18:58

httpclient 连接池测试的相关文章

HttpClient连接池的一些思考

前言 使用apache的httpclient进行http的交互处理已经很长时间了,而httpclient实例则使用了http连接池,想必大家也没有关心过连接池的管理.事实上,通过分析httpclient源码,发现它很优雅地隐藏了所有的连接池管理细节,开发者完全不用花太多时间去思考连接池的问题. Apache官网例子 CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet

HttpClient连接池

HttpClient连接池的连接保持.超时和失效机制 HTTP是一种无连接的事务协议,底层使用的还是TCP,连接池复用的就是TCP连接,目的就是在一个TCP连接上进行多次的HTTP请求从而提高性能.每次HTTP请求结束的时候,HttpClient会判断连接是否可以保持,如果可以则交给连接管理器进行管理以备下次重用,否则直接关闭连接.这里涉及到三个问题: 1.如何判断连接是否可以保持? 要想保持连接,首先客户端需要告诉服务器希望保持长连接,这就是所谓的Keep-Alive模式(又称持久连接,连接重

HttpClient连接池之CLOSE_WAIT

HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查 今天解决了一个HttpClient的异常,汗啊,一个HttpClient使用稍有不慎都会是毁灭级别的啊. 这里有之前因为route配置不当导致服务器异常的一个处理:http://blog.csdn.net/shootyou/article/details/6415248 里面的HttpConnectionManager实现就是我在

HttpClient连接池的连接保持、超时和失效机制

HTTP是一种无连接的事务协议,底层使用的还是TCP,连接池复用的就是TCP连接,目的就是在一个TCP连接上进行多次的HTTP请求从而提高性能.每次HTTP请求结束的时候,HttpClient会判断连接是否可以保持,如果可以则交给连接管理器进行管理以备下次重用,否则直接关闭连接.这里涉及到三个问题: 1.如何判断连接是否可以保持? 要想保持连接,首先客户端需要告诉服务器希望保持长连接,这就是所谓的Keep-Alive模式(又称持久连接,连接重用),HTTP1.0中默认是关闭的,需要在HTTP头加

HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查

今天解决了一个HttpClient的异常,汗啊,一个HttpClient使用稍有不慎都会是毁灭级别的啊. 这里有之前因为route配置不当导致服务器异常的一个处理:http://blog.csdn.net/shootyou/article/details/6415248 里面的HttpConnectionManager实现就是我在这里使用的实现. 问题表现: tomcat后台日志发现大量异常 [plain] view plain copy print? org.apache.http.conn.

Apache HttpClient 连接池的使用

import java.io.IOException;import java.util.Random; import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.

Http请求连接池 - HttpClient 的 PoolingHttpClientConnectionManager

两个主机建立连接的过程是非常复杂的一个过程,涉及到多个数据包的交换,而且也非常耗时间.Http连接须要的三次握手开销非常大,这一开销对于比較小的http消息来说更大.但是假设我们直接使用已经建立好的http连接.这样花费就比較小.吞吐率更大. 传统的HttpURLConnection并不支持连接池.假设要实现连接池的机制,还须要自己来管理连接对象.对于网络请求这种底层相对复杂的操作.个人以为假设有可用的其它方案,也没有必要自己去管理连接对象. 除了HttpURLConnection,大家肯定还知

HttpClient 4.3连接池参数配置及源码解读

目前所在公司使用HttpClient 4.3.3版本发送Rest请求,调用接口.最近出现了调用查询接口服务慢的生产问题,在排查整个调用链可能存在的问题时(从客户端发起Http请求->ESB->服务端处理请求,查询数据并返回),发现原本的HttpClient连接池中的一些参数配置可能存在问题,如defaultMaxPerRoute.一些timeout时间的设置等,虽不能确定是由于此连接池导致接口查询慢,但确实存在可优化的地方,故花时间做一些研究.本文主要涉及HttpClient连接池.请求的参数

最近学习了Http连接池

起因 6.1大促值班发现的一个问题,一个rpc接口在0~2点用户下单高峰的时候表现rt高(超过1s,实际上针对性优化过的接口rt超过这个值也是有问题的,通常rpc接口里面即使逻辑复杂,300ms应该也搞定了),可以理解,但是在4~5点的时候接口的tps已经不高了,耗时依然在600ms~700ms之间就不能理解了. 查了一下,里面有段调用支付宝http接口的逻辑,但是每次都new一个HttpClient出来发起调用,调用时长大概在300ms+,所以导致即使在非高峰期接口耗时依然非常高. 问题不难,