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