簡單利用PoolingHttpClientConnectionManager來優化HttpClient方法,避免httpclient導致的java.net.SocketException: Network is unreachable (connect failed)


簡單利用PoolingHttpClientConnectionManager來優化HttpClient方法,避免httpclient導致的排隊堆積從而引發java.net.SocketException: Network is unreachable (connect failed)

背景描述(無關問題,可以忽略):

之前因為公司數據庫訪問速度太慢,導致我所負責的模塊查詢效率也及低,所以對其數據庫方面做了優化,因為sql已經沒有太多的優化空間了,所以就對數據庫表做了調整。優化過程主要是將幾張舊表中合法有效的數據轉移到一張新表上,這樣避免了每次查詢的排查數據是否合法,也省去了兩表聯查三表聯查等降低查詢效率的字段。
而問題就出在將舊表數據轉移到新表上時,有很多斷鏈需要處理掉。我首先想到的是用HttpClient直接逐個請求,返回200保存到新表中,非200則丟棄。就這樣,問題來了:

問題描述

HttpClient連接沒有做關閉操作,導致new的httpclient過多造成tomcat假死 or DB死鎖。

解決思路

利用httpclient池化技術來保證請求的數量,並且及時關閉無效的請求。

實現過程,直接上代碼了

幫助類

/**
 * httpclient池工具類
 * @Author: zhuyu
 * @Date: Create in 18:40:09 2020年12月20日 0020
 */
public class HttpClientHelper {

    static PoolingHttpClientConnectionManager clientPool = new PoolingHttpClientConnectionManager();

    // httpclient請求超時配置
    static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();

    // 將需要配置的值都放到靜態代碼塊中,類被加載時,靜態代碼塊也會被加載
    static {
        // 最大連接請求數
        clientPool.setMaxTotal(5);
        // 最大路由連接數
        clientPool.setDefaultMaxPerRoute(5);
    }
        // 通過getHttpclientPool方法來獲取httpclient,避免了直接去手動new
    public static CloseableHttpClient getHttpclientPool() {
        return HttpClients.custom().setConnectionManager(clientPool).setDefaultRequestConfig(requestConfig).build();
    }
}

功能實現類

class Test {

    private static final int SUCCESS_CODE = 200;

    private static final String Read_Timed_Out_ERROR = "Read timed out";

    public static void main(String[] args) {
        // 開始時間
        long startTime = System.currentTimeMillis();
        // 請求鏈接
        String requestHref = "http://www.baidu.com";
        // 從HttpClient連接池中獲取httpclient
        CloseableHttpClient httpClient = HttpClientHelper.getHttpclientPool();
        int times = 0;
        for (int i = 0; i < 50; i++) {
            HttpGet httpGet = new HttpGet(requestHref);
            try {
                CloseableHttpResponse response = httpClient.execute(httpGet);
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != SUCCESS_CODE) {
                    System.out.println("發現斷鏈");
                }
                times++;
            } catch (Exception e) {
                if (Read_Timed_Out_ERROR.equals(e.getMessage())) {
                    System.out.println("連接超時");
                } else {
                    System.out.println("e.getMessage() = " + e.getMessage());
                }
            }finally {
                httpGet.releaseConnection();
            }
        }
        System.out.println("本次請求一共耗時:{" + (System.currentTimeMillis() - startTime) + "}"+"共請求次數 :"+times);
    }
}

最后測試,大功告成。需要注意的是:

實現過程的bug

利用單例模式創建httpclient pool后,直接用httpclienthelper創建了httpclient,然后在關閉時遇到了問題,因為之前設置的最大連接數是5,

所以導致httpclient訪問5次后就卡住了,說明請求沒有被釋放。

嘗試直接close httpclient,但這樣會導致Connection pool shut down

最終只能把希望寄托於httpGet上了,進入httpGet中尋找方法,果不其然!!

CloseableHttpResponse是可以刷新請求內部狀態的,這樣既可以使得pool中的五個連接繼續發起請求,又可以避免new太多httpclient。

結語:一般如果要重復使用httpclient時,推薦使用連接池去操作,但如果只是請求幾次,那么直接new也沒什么關系,不過要記得close


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM