<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          網(wǎng)關(guān)使用 Apache HttpClient 連接池出現(xiàn)異常

          共 4888字,需瀏覽 10分鐘

           ·

          2022-06-10 04:13


          最近網(wǎng)關(guān)發(fā)版出現(xiàn)大量如下異常,而有如下文章:

          org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool


          兩個(gè)主機(jī)建立網(wǎng)絡(luò)連接是一個(gè)比較復(fù)雜的過程,涉及到多個(gè)數(shù)據(jù)包的交換。建立網(wǎng)絡(luò)連接本身就很耗時(shí)間,而 Http 連接需要三次握手,開銷就更大。但是可以直接使用已經(jīng)建立好的 Http?連接,那么花費(fèi)就比較小。耗時(shí)更短,從而提高訪問的吞吐量。


          傳統(tǒng)的 HttpURLConnection 并不支持連接池,如果要實(shí)現(xiàn)連接池機(jī)制,那么需要自己來管理連接對(duì)象。對(duì)于網(wǎng)絡(luò)請(qǐng)求這種底層相對(duì)復(fù)雜的操作,沒有一定經(jīng)驗(yàn)的程序員很難寫好這塊代碼邏輯。


          除了 HttpURLConnection,常用的Http Client 要數(shù) Apache 的 HttpClient。一般情況下, HttpClient 已經(jīng)能滿足業(yè)務(wù)需求了;但是在網(wǎng)關(guān)這種高并發(fā)場(chǎng)景下,使用 HttpClient? 進(jìn)行大量的請(qǐng)求網(wǎng)絡(luò),還是需要用連接池才能提高網(wǎng)關(guān)的TPS,不然很容易成為網(wǎng)關(guān)的瓶頸。


          Apache 的?HttpClient的早期版本,提供了PoolingClientConnectionManager、DefaultHttpClient 等類來實(shí)現(xiàn) Http?連接池,但這些類在 4.3.x 版本之后大部分已過時(shí)。后續(xù)版本提供了PoolingHttpClientConnectionManager 等類進(jìn)行 Http??連接池的實(shí)現(xiàn)。PoolingHttpClientConnectionManager 是一個(gè) Http 連接池管理器,用來服務(wù)于多線程時(shí)并發(fā)獲取連接的請(qǐng)求。每個(gè)路由(IP)將池化不大于 defaultMaxPerRoute 參數(shù)的連接。


          pom.xml?文件引入依賴

          <dependency>?????<groupId>org.apache.httpcomponentsgroupId>??????<artifactId>httpclientartifactId>??????<version>4.5.13version>dependency><dependency>????  <groupId>org.apache.httpcomponentsgroupId>?????  <artifactId>httpcoreartifactId>???????<version>4.4.15version>dependency><dependency>        <groupId>org.apache.httpcomponentsgroupId>        <artifactId>httpclient-cacheartifactId>??????<version>4.5.13version>dependency>

          定義連接池主要參數(shù)

          public?class?HttpPoolProperties?{
          private Integer maxTotal;
          ????private?Integer?maxRoute; private Integer defaultMaxPerRoute;
          private String hostName;
          private Integer port;
          private Integer connectTimeout;
          private Integer connectionRequestTimeout;
          ????private?Integer?socketTimeout;
          private Integer validateAfterInactivity;
          ????//?TODO 省略get set 方法}
          • maxTotal:允許跨所有路線的最大連接數(shù)

          • defaultMaxPerRoute:所有路由默認(rèn)最大連接數(shù)

          • maxPerRoute:指定某個(gè)路由的最大連接數(shù)

          defaultMaxPerRoute?與?maxPerRoute?這兩個(gè)參數(shù)存在優(yōu)先級(jí)關(guān)系。具體可以參看 AbstractConnPool 類的如下方法的引用關(guān)系

          private int getMax(T route) {??? Integer?v?=?(Integer)this.maxPerRoute.get(route);    return v != null ? v : this.defaultMaxPerRoute;}
          • connectTimeout:多久等待與遠(yuǎn)程服務(wù)器拋出超時(shí)異常之前建立連接

          • socketTimeout:多久等待服務(wù)器拋出超時(shí)異常之前,各種消息響應(yīng)

          http://docs.oracle.com/javase/1.5.0/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
          • connectionRequestTimeout:多久試圖拋出異常之前,先從連接池中的連接時(shí)等待(連接池不會(huì)立即返回,如果所有的連接被檢出)

          • staleConnectionCheckEnabled:可以在潛在的 IOExceptions 成本的性能有所提高被禁用

          http://hc.apache.org/httpclient-3.x/performance.html#Stale_connection_check


          獲取 HttpClient 對(duì)象

          public static CloseableHttpClient createHttpClient(HttpPoolProperties httpPoolProperties) {        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();        Registry registry = RegistryBuilder                . create().register("http", plainsf)                .register("https", sslsf).build();        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(                registry);        // 將最大連接數(shù)增加        cm.setMaxTotal(httpPoolProperties.getMaxTotal());        // 將每個(gè)路由基礎(chǔ)的連接增加        cm.setDefaultMaxPerRoute(httpPoolProperties.getDefaultMaxPerRoute());        if(StringUtils.hasText(httpPoolProperties.getHostName()) && httpPoolProperties.getPort()!=null) {            HttpHost httpHost = new HttpHost(httpPoolProperties.getHostName(), httpPoolProperties.getPort());            // 將目標(biāo)主機(jī)的最大連接數(shù)增加            cm.setMaxPerRoute(new HttpRoute(httpHost), httpPoolProperties.getMaxRoute());        }        // 請(qǐng)求重試處理        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {                // 如果已經(jīng)重試了5次,就放棄                if (executionCount >= 5) {                        return false;                }??????????????????//?如果服務(wù)器丟掉了連接,那么就重試                if (exception instanceof NoHttpResponseException) {                        return true;                }                // 不要重試SSL握手異常                if (exception instanceof SSLHandshakeException) {                        return false;                }                // 超時(shí)                if (exception instanceof InterruptedIOException) {                        return false;                }                // 目標(biāo)服務(wù)器不可達(dá)????????????????if?(exception?instanceof?UnknownHostException)?{                        return false;                }                // 連接被拒絕                if (exception instanceof ConnectTimeoutException) {                        return false;                }                // SSL握手異常                if (exception instanceof SSLException) {                        return false;                }

          HttpClientContext clientContext = HttpClientContext .adapt(context); HttpRequest request = clientContext.getRequest(); // 如果請(qǐng)求是冪等的,就再次嘗試 if (!(request instanceof HttpEntityEnclosingRequest)) { return true; } return false; } }; CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(cm) .setRetryHandler(httpRequestRetryHandler).build(); return httpClient;}


          記得點(diǎn)「」和「在看」↓

          愛你們

          瀏覽 65
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩欧美亚洲一区二区三区 | 三级av二区 | 91大鸡巴| 天天爱天天做天天大综合 | 日韩人妻一区 |