1. 程式人生 > >HttpClient 連線池的簡單實現

HttpClient 連線池的簡單實現

最近在做Druid大資料實時分析系統,以Http的方式向Druid叢集寫入資料,採用HttpClient向叢集提交資料,由於資料量較大,採用多執行緒的方式開啟了10個執行緒後,發現單個的HttpClient會出現連線超時,效率不高,所以想用到連線池的方式提高效率下面是一個簡單的HttpClient連線池的實現:

package com.ssm.httpclient.utils;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.apache.http.client.config.RequestConfig
; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.config.SocketConfig; import org.apache.http.conn.DnsResolver; import org.apache.http.conn.HttpConnectionFactory; import org.apache.http.conn.ManagedHttpClientConnection; import org.apache.http
.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.client
.CloseableHttpClient; import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.DefaultHttpResponseParserFactory; import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.SystemDefaultDnsResolver; import org.apache.http.impl.io.DefaultHttpRequestWriterFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HttpClientUtils { private static final Logger LOG = LoggerFactory.getLogger(HttpClientUtils.class); static PoolingHttpClientConnectionManager manager = null; static CloseableHttpClient httpClient = null; public static synchronized CloseableHttpClient getHttpClient(){ if(httpClient == null){ //註冊訪問協議相關的Socket工廠 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", SSLConnectionSocketFactory.getSystemSocketFactory()) .build(); //HttpConnection 工廠:配置寫請求/解析響應處理器 HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connectionFactory = new ManagedHttpClientConnectionFactory(DefaultHttpRequestWriterFactory.INSTANCE, DefaultHttpResponseParserFactory.INSTANCE); //DNS 解析器 DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE; //建立池化連線管理器 manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry,connectionFactory,dnsResolver); //預設為Socket配置 SocketConfig defaultSocketConfig = SocketConfig.custom().setTcpNoDelay(true).build(); manager.setDefaultSocketConfig(defaultSocketConfig); manager.setMaxTotal(300); //設定整個連線池的最大連線數 //每個路由的預設最大連線,每個路由實際最大連線數由DefaultMaxPerRoute控制,而MaxTotal是整個池子的最大數 //設定過小無法支援大併發(ConnectionPoolTimeoutException) Timeout waiting for connection from pool manager.setDefaultMaxPerRoute(200);//每個路由的最大連線數 //在從連線池獲取連線時,連線不活躍多長時間後需要進行一次驗證,預設為2s manager.setValidateAfterInactivity(5*1000); //預設請求配置 RequestConfig defaultRequestConfig = RequestConfig.custom() .setConnectTimeout(2*1000) //設定連線超時時間,2s .setSocketTimeout(5*1000) //設定等待資料超時時間,5s .setConnectionRequestTimeout(2000) //設定從連線池獲取連線的等待超時時間 .build(); //建立HttpClient httpClient = HttpClients.custom() .setConnectionManager(manager) .setConnectionManagerShared(false) //連線池不是共享模式 .evictIdleConnections(60, TimeUnit.SECONDS) //定期回收空閒連線 .evictExpiredConnections()// 定期回收過期連線 .setConnectionTimeToLive(60, TimeUnit.SECONDS) //連線存活時間,如果不設定,則根據長連線資訊決定 .setDefaultRequestConfig(defaultRequestConfig) //設定預設請求配置 .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE) //連線重用策略,即是否能keepAlive .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE) //長連線配置,即獲取長連線生產多長時間 .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)) //設定重試次數,預設是3次,當前是禁用掉(根據需要開啟) .build(); //JVM 停止或重啟時,關閉連線池釋放掉連線(跟資料庫連線池類似) Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run() { try{ if(httpClient !=null){ httpClient.close(); } }catch(IOException e){ LOG.error("error when close httpClient:{}",e); } } }); } return httpClient; } }

基於HttpClientUtils的測試

package com.ssm.httpclient.utils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;

public class HttpClientExample {

    public static void main(String[] args) {

        final ThreadFactory threadFactory = new ThreadFactoryBuilder()
        .setNameFormat("Orders-%d").build();

        ExecutorService executorService = Executors.newFixedThreadPool(10,threadFactory);

        List<Future<?>> list = Lists.newArrayList();

        Long startTime = System.currentTimeMillis();

        Future<?> future;
        for(int i=0;i<100;i++){
            future = executorService.submit((new HttpGetTest()));
            list.add(future);
        }

        for(Future<?> future2:list){
            try {
                future2.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

        System.out.println("total cost times: "+(System.currentTimeMillis()-startTime));

        executorService.shutdown();
    }

}

class HttpGetTest implements Runnable {

    public void run() {

        HttpResponse response = null;

        try {

            HttpGet get = new HttpGet("https://baike.baidu.com/item/httpclient/5766483?fr=aladdin");

            response = HttpClientUtils.getHttpClient().execute(get);

            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                EntityUtils.consume(response.getEntity());
            } else {
                String result = EntityUtils.toString(response.getEntity(),Charset.forName("utf-8"));
                System.out.println(result);
            }

        } catch (Exception e) {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }

    }

}

total cost times: 3248

一百個執行緒請求花了3s 多,效能還是可以

相關推薦

【設計模式】之物件模式--JDBC連線簡單實現案例

文章目錄 物件池設計模式 物件池設計模式的目標 問題 討論 結構 示例 核驗單 經驗法則 連線池模式示例程式碼 ObjectPool.java

HttpClient 連線簡單實現

最近在做Druid大資料實時分析系統,以Http的方式向Druid叢集寫入資料,採用HttpClient向叢集提交資料,由於資料量較大,採用多執行緒的方式開啟了10個執行緒後,發現單個的HttpClient會出現連線超時,效率不高,所以想用到連線池的方式提高效率

一個簡單資料庫連線實現

一、已實現功能   資料庫連線快取。將資料庫連線與執行緒ID繫結並提供執行資料庫操作時檢測。資料庫連線超時檢測。初始化資料庫環境,包括初始化資料庫,資料庫使用者,資料庫表。 二、程式碼列表: 1、MySqlDBManager:   用於管理資料庫配置、初始化資料庫環境及建立

httpcomponents httpclient連線實現與測試

在windows環境下,使用Process Explorer檢視連線數和連線狀態。 package http.connection

Hive使用druid做連線程式碼實現

配置文件 hive_jdbc_url=jdbc:hive2://192.168.0.22:10000/default hive.dbname=xxxxx hive_jdbc_username=root hive_jdbc_password=123456 #配置初始化大小、最小、最大 hiv

AIDL連線實現

參考《Android開發藝術探索》學習一下AIDL的連線池實現 回顧一下AIDL使用的大致流程:首先建立一個Service和一個AIDL介面,接著建立一個類繼承自AIDL介面中的Stub類並實現Stub中的抽象方法,在Service的onBind方法中返回這個類的物件,然後客戶端就可以繫

golang go-sql-drive mysql連線實現 golang go-sql-drive mysql連線實現

golang go-sql-drive mysql連線池的實現 golang內部自帶了連線池功能,剛開始接觸golang的時候不瞭解這個,還自己搞了一個 sql.Open的物件管理池,真的非常囧啊。 sql.Open函式實際上是返回

golang sql連線實現解析 golang sql連線實現解析

golang sql連線池的實現解析 golang的”database/sql”是操作資料庫時常用的包,這個包定義了一些sql操作的介面,具體的實現還需要不同資料庫的實現,mysql比較優秀的一個驅動是:github.com/go-sql-dri

【Elasticsearch】Java Client連線程式碼實現

用過Elasticsearch API的都知道,在Java端使用是ES服務需要建立Java Client,但是每一次連線都例項化一個client,對系統的消耗很大,而且最令人頭疼的是它的連線非常慢。所以為了解決上述問題並提高client利用率,用池化技術複用client,第一次用去建立cli

httpclient連線的配置方法

HttpClient和Lucene一樣,每個版本的API都變化很大,這有點讓人頭疼。 筆者碰到的情況最早在hadoop環境用httpclient發起httpjson請求,在本地除錯的時候用的4.5.2版本,放到hadoop環境中執行報錯,無奈只好將httpclient降級成

服務間呼叫httpclient連線異常

本文轉自:https://blog.csdn.net/hry2015/article/details/78965690 1. 問題描述 客戶端A –> Ngnix –> 服務B  Ngnix做服務B的負載,客戶端訪問服務B時,客戶端偶爾會有丟擲TimeoutExcept

redis分散式連線程式碼實現

redis分散式演算法原理: 本例中我們打開了兩個redis服務,一個6379埠,一個6380埠,那麼我們儲存資料的時候是怎麼分配的了,object1經過hsah到了他的位置上,存放到cacheA節點上,其它如object2,object3,object4也到了各自的位置,每個如cacheA的節點其實就

Android推送的核心原理:長連線簡單實現

實際需求 移動端需要實時的獲取伺服器的資料 解決方案 輪詢方式:應用程式開啟定時的輪詢,不停的向伺服器請求資料。 SMS push:傳送二進位制簡訊到移動終端,來達到通知終端的目的。客戶端攔截這類簡訊,然後採取相應的操作 持久連線方式:應用程式與伺服

RabbitMQ客戶連線實現

目前RabbitMQ官方給的出的客戶端傳送訊息的Demo的都是基於短連線來做的,例如: ConnectionFactory cf = new ConnectionFactory(); cf.Uri = serverAddress; using (IConn

HttpClient連線丟擲大量ConnectionPoolTimeoutException: Timeout waiting for connection異常排查

今天解決了一個HttpClient的異常,汗啊,一個HttpClient使用稍有不慎都會是毀滅級別的啊。裡面的HttpConnectionManager實現就是我在這裡使用的實現。問題表現:tomcat後臺日誌發現大量異常org.apache.http.conn.Connec

java之執行緒簡單實現

以前做的東西,實現一個簡單的多執行緒機制,開始之前,現說說原理性的東西吧,下面是我在ibm開發者上搜到的內容 執行緒池的技術背景   在面向物件程式設計中,建立和銷燬物件是很費時間的,因為建立一個物件要獲取記憶體資源或者其它更多資源。在Java中更是如此,虛擬機器將

HttpClient連線原理及一次連線時序圖

HttpClient是一個實現了http協議的開源Java客戶端工具庫,可以通過程式傳送http請求。 1.1.HttpClient傳送請求和接收響應 1.1.1.程式碼示例 以Get請求為例,以下程式碼獲得google主頁內容並將返回結果打印出

HttpClient連線連線保持、超時和失效機制

HTTP是一種無連線的事務協議,底層使用的還是TCP,連線池複用的就是TCP連線,目的就是在一個TCP連線上進行多次的HTTP請求從而提高效能。每次HTTP請求結束的時候,HttpClient會判斷連線是否可以保持,如果可以則交給連線管理器進行管理以備下次重用,否則直接關閉連線。這裡涉及到三個問題: 1、如

MongoDB連線實現

幾乎每一種資料庫都會有連線池, 來減少頻繁的建立刪除連線的開銷, 在MongoDB裡面是通過訊號量執行緒同步方式來對建立、銷燬進行管理。 訊號量基礎 int sem_init(sem_t *sem, int pshared, unsigned int value) sem是

Oracle資料庫連線實現

資料連線池的工做機制:J2EE伺服器啟動時會建立一定數量的池連線,並一直維持不少此數目的池連線。客戶端程式需要連線時,池驅動程式會返回一個未使用的池連線並將其表記為忙。如果當前沒有空閒連線,池驅動程式就新建一定數量的連線,新建連線的數量有配置引數決定。當使用的池連線呼叫完成後,池驅動程式將此連線