HttpClient大併發下Timeout waiting for connection from pool 問題解決方案
阿新 • • 發佈:2019-01-23
錯誤:org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
前言 :
第一次看到這個錯誤, 上網找了下,有文章說是連線池不夠了。。。。 並沒有多想,立即將原有程式的 連結池擴容了3倍,然後單個路由 擴容了5倍。
問題解決, 以為找到了,答案。 但是 過了大約 幾天之後,再次出現該問題,當時就特別疑惑, 沒有擴容之前 程式已經運行了 將近兩年,並沒有發生任何錯誤,
現在 擴容了,竟然還報這個錯, 此時 分析方向 應該發生改變。
懷疑方向一 : 大量的Timeout 出現,是否 請求的域名有問題 ?
於是,手動 ping 了訪問域名,發現並沒有多慢. (疑問否決)
懷疑方向二 : 是否我們伺服器出口IP 有問題, 請求 指定域名 超時?
於是: 我們新開了一臺機器, 然後將 原有的兩臺機器 停掉一臺, 並且新開的機器 使用 全新的出口IP, 以區分於原有機器,後來發現 新卡的機器,沒有問題。
因此,我們大致定位了問題,就是 伺服器的出口IP 有問題, 並不是程式的問題。 所以,解決方案就是 找運維 重新申請配置了機器.
下面 貼出 我連線池的 寫法, 做個小筆記 。
HttpClient 版本如下
連線池程式碼如下 :<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.4</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.3.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.3.1</version> </dependency>
以下 執行緒用來清理 連線池無效的連結 :package com.**.weixin.common.https; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; public class HttpClientFactory { private static final Integer MAX_TOTAL = 300; //連線池最大連線數 private static final Integer MAX_PER_ROUTE = 50; //單個路由預設最大連線數 private static final Integer REQ_TIMEOUT = 5 * 1000; //請求超時時間ms private static final Integer CONN_TIMEOUT = 5 * 1000; //連線超時時間ms private static final Integer SOCK_TIMEOUT = 10 * 1000; //讀取超時時間ms private static HttpClientConnectionMonitorThread thread; //HTTP連結管理器執行緒 public static HttpClientConnectionMonitorThread getThread() { return thread; } public static void setThread(HttpClientConnectionMonitorThread thread) { HttpClientFactory.thread = thread; } public static HttpClient createSimpleHttpClient(){ SSLConnectionSocketFactory sf = SSLConnectionSocketFactory.getSocketFactory(); return HttpClientBuilder.create() .setSSLSocketFactory(sf) .build(); } public static HttpClient createHttpClient() { PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(); poolingHttpClientConnectionManager.setMaxTotal(MAX_TOTAL); poolingHttpClientConnectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE); RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(REQ_TIMEOUT) .setConnectTimeout(CONN_TIMEOUT).setSocketTimeout(SOCK_TIMEOUT) .build(); HttpClientFactory.thread=new HttpClientConnectionMonitorThread(poolingHttpClientConnectionManager); //管理 http連線池 return HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager).setDefaultRequestConfig(requestConfig).build(); } }
package com.**.weixin.common.https;
import java.util.concurrent.TimeUnit;
import org.apache.http.conn.HttpClientConnectionManager;
/**
* <p>Description: 使用管理器,管理HTTP連線池 無效連結定期清理功能</p>
* @author andy 2017年8月28日
*/
public class HttpClientConnectionMonitorThread extends Thread {
private final HttpClientConnectionManager connManager;
private volatile boolean shutdown;
public HttpClientConnectionMonitorThread(HttpClientConnectionManager connManager) {
super();
this.setName("http-connection-monitor");
this.setDaemon(true);
this.connManager = connManager;
this.start();
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000); // 等待5秒
// 關閉過期的連結
connManager.closeExpiredConnections();
// 選擇關閉 空閒30秒的連結
connManager.closeIdleConnections(30, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
}
}
/**
* 方法描述: 停止 管理器 清理無效連結 (該方法當前暫時關閉)
* @author andy 2017年8月28日 下午1:45:18
*/
@Deprecated
public void shutDownMonitor() {
synchronized (this) {
shutdown = true;
notifyAll();
}
}
}