欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用HTTPclient保持長連接

 更新時(shí)間:2021年10月23日 11:59:11   作者:MrHamster  
這篇文章主要介紹了使用HTTPclient保持長連接,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

HTTPclient保持長連接

首先解釋一下什么是長連接

當(dāng)我們向一臺(tái)服務(wù)器發(fā)起請(qǐng)求時(shí),我們需要和對(duì)方建立一條通道,去傳輸數(shù)據(jù),所謂的短連接,就是說我們建立起了通道,然后在傳輸完數(shù)據(jù),就把通道摧毀,下次需要的時(shí)候再重新去建立通道。

長連接呢,就是指,我們建立了一條通道,傳遞完數(shù)據(jù)后,先不摧毀,下次如果還需要傳輸數(shù)據(jù),就復(fù)用這條通道。

因?yàn)橥ǖ赖慕⑹切枰ㄙM(fèi)時(shí)間的,所以長連接的優(yōu)勢(shì)就在于響應(yīng)速度快,但是服務(wù)器壓力大,因?yàn)橥瑫r(shí)有很多人在向服務(wù)器建立通道,即便有些通道已經(jīng)傳輸完數(shù)據(jù)了,由于長連接的原因,通道也不會(huì)被摧毀;短連接呢,則是,響應(yīng)速度慢,服務(wù)器壓力小。

由于現(xiàn)在更多的是強(qiáng)調(diào)用戶的體驗(yàn),所以長連接目前是最常見的。

如何在java中實(shí)現(xiàn)一個(gè)長連接呢

其實(shí)很簡單,只需要在請(qǐng)求的請(qǐng)求頭中加入特定的參數(shù) :“Connection”:"keep-alive"即可。這樣如果對(duì)方支持長連接的話,那么這個(gè)連接就會(huì)保持長連接了。

問題的關(guān)鍵就來了,在一次壓測(cè)某個(gè)https請(qǐng)求響應(yīng)速度的代碼中,我發(fā)現(xiàn)了,當(dāng)對(duì)方響應(yīng)數(shù)據(jù)為null,也就是responseBody中帶的數(shù)據(jù)為null時(shí),響應(yīng)速度特別快,大概在5ms左右,但是一旦對(duì)方返回了響應(yīng)數(shù)據(jù),本次響應(yīng)就可能達(dá)到了20ms。

然后請(qǐng)運(yùn)維同事抓包,發(fā)現(xiàn)每次連接,都會(huì)耗費(fèi)時(shí)間在用戶認(rèn)證上,其實(shí)也就是從某個(gè)方面反應(yīng)出,每次都是新建立了一個(gè)連接。

HttpPost httpPost = new HttpPost("xxxxx");
httpPost.addHeader("Connection", "keep-alive");
CloseableHttpClient httpClient = null;
for(int i =0 ;i<5000;i++){
    long t1 = System.currentTimeMillis();
	CloseableHttpResponse response = httpClient.execute(httpPost);
	long t2 = System.currentTimeMillis();
}

上了一段簡單的代碼,表示一下大概的邏輯,實(shí)際的壓測(cè)代碼還包括了線程池,連接池的完整參數(shù)等等,如果需要的可以留言或者翻看本人的其他的博客,有寫線程池和連接池。

就是這樣一段代碼,導(dǎo)致每次連接都是新建立的連接,那么原因是什么呢,我們先上代碼:

for (int i = 0; i<5000;i++){
     long t1 = System.currentTimeMillis();
      CloseableHttpResponse response = httpClient.execute(httpPost);
      if(null != response.getEntity()){
           EntityUtils.consume(response.getEntity());
      }
      long t2 = System.currentTimeMillis();
 }

我們只需要簡單加上三行代碼,就可以解決這個(gè)問題了,這是為什么呢,讓我們點(diǎn)進(jìn)去源碼看一下

在這里插入圖片描述

這么一看, 其實(shí)這個(gè)方法也并沒有做什么,只是簡單的取到了流去關(guān)閉,為什么就保持長連接了呢。

后來仔細(xì)讀http連接的原理才得知,當(dāng)一個(gè)連接建立,響應(yīng)數(shù)據(jù)時(shí),會(huì)封裝CloseableHttpResponse這個(gè)對(duì)象里面,其中的Entity對(duì)象就是包含著響應(yīng)體的數(shù)據(jù),我們需要用流去獲取。如果你不去獲取,那么這個(gè)數(shù)據(jù)就會(huì)存在于這個(gè)對(duì)象中,連接池就會(huì)認(rèn)為,這個(gè)通道里有未處理的數(shù)據(jù),然后它不會(huì)去復(fù)用這個(gè)通道,而是選擇重建一個(gè)通道。這就完美解釋了為什么壓測(cè)時(shí),對(duì)方返回null時(shí),響應(yīng)速度特別快,而攜帶返回?cái)?shù)據(jù)時(shí),響應(yīng)速度特別慢了。

那么再仔細(xì)想想,為什么我們平常不知道這個(gè)知識(shí)點(diǎn),卻從來沒有報(bào)過錯(cuò)呢,那是因?yàn)檎G闆r下,我們都是需要會(huì)對(duì)response做處理,比如String responseContent = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); 類似這種,我們點(diǎn)進(jìn)源碼看,其實(shí)也是取到了流,并做了關(guān)閉操作。平常還是要多閱讀源碼,想想源碼。

httpclient因?yàn)楸3钟谰瞄L連接造成連接吊死的問題

httpclient使用了連接池,如果沒有設(shè)置keep-alive策略,PoolingHttpClientConnectionManager會(huì)默認(rèn)使用永久連接。

最近在調(diào)用京東api時(shí),發(fā)現(xiàn)一個(gè)請(qǐng)求開始是可以獲取到數(shù)據(jù)的,但隔了兩分鐘后再請(qǐng)求就會(huì)出現(xiàn)read timeout異常。

對(duì)比請(qǐng)求成功和請(qǐng)求失敗的日志后發(fā)現(xiàn),請(qǐng)求成功的有以下日志“Connection: keep-alive”,“Connection can be kept alive indefinitely”;但請(qǐng)求失敗的卻打印“Shutdown connection”,“Connection discarded”。

每次失敗后再請(qǐng)求都會(huì)成功。因此推測(cè)中應(yīng)該是對(duì)方服務(wù)器端禁止長連接,當(dāng)連接到達(dá)一定時(shí)間會(huì)就會(huì)斷開。

后來上網(wǎng)找到keep-alive策略的代碼。

添加策略后,問題解決

ConnectionKeepAliveStrategy keepAliveStrategy = new ConnectionKeepAliveStrategy() {
            @Override
            public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                while (it.hasNext()) {
                    HeaderElement he = it.nextElement();
                    String param = he.getName();
                    String value = he.getValue();
                    if (value != null && param.equalsIgnoreCase("timeout")) {
                        try {
                            return Long.parseLong(value) * 1000;
                        }
                        catch (NumberFormatException ignore) {
                        }
                    }
                }
                HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST);
                if ("bizapi.jd.com ".equalsIgnoreCase(target.getHostName())) {
                    return 60 * 1000;
                }
                else {
                    return 300 * 1000;
                }
   CloseableHttpClient httpClient = httpClientBuilder.setConnectionManager(pollingConnectionManager)
                .setKeepAliveStrategy(keepAliveStrategy).setDefaultRequestConfig(defaultRequestConfig).build();

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java如何自動(dòng)補(bǔ)齊數(shù)值至指定位數(shù)

    java如何自動(dòng)補(bǔ)齊數(shù)值至指定位數(shù)

    這篇文章主要介紹了java如何自動(dòng)補(bǔ)齊數(shù)值至指定位數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Jmeter后置處理器實(shí)現(xiàn)過程及方法應(yīng)用

    Jmeter后置處理器實(shí)現(xiàn)過程及方法應(yīng)用

    這篇文章主要介紹了Jmeter后置處理器實(shí)現(xiàn)過程及方法應(yīng)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java中獲取List中最后一個(gè)元素的三種方法

    Java中獲取List中最后一個(gè)元素的三種方法

    在Java編程中我們經(jīng)常需要獲取一個(gè)List集合中的最后一個(gè)元素,這篇文章主要給大家介紹了關(guān)于Java中獲取List中最后一個(gè)元素的三種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • SpringBoot?整合RabbitMq?自定義消息監(jiān)聽容器來實(shí)現(xiàn)消息批量處理

    SpringBoot?整合RabbitMq?自定義消息監(jiān)聽容器來實(shí)現(xiàn)消息批量處理

    Spring Boot中提供了默認(rèn)的監(jiān)聽器容器,但是有時(shí)候我們需要自定義監(jiān)聽器容器,來滿足一些特殊的需求,比如批量獲取數(shù)據(jù),這篇文章主要介紹了SpringBoot?整合RabbitMq?自定義消息監(jiān)聽容器來實(shí)現(xiàn)消息批量處理,需要的朋友可以參考下
    2023-04-04
  • java中哈希表及其應(yīng)用詳解

    java中哈希表及其應(yīng)用詳解

    Java中哈希表(Hashtable)是如何實(shí)現(xiàn)的呢?Hashtable中有一個(gè)內(nèi)部類Entry,用來保存單元數(shù)據(jù),我們用來構(gòu)建哈希表的每一個(gè)數(shù)據(jù)是Entry的一個(gè)實(shí)例。假設(shè)我們保存下面一組數(shù)據(jù),第一列作為key, 第二列作為value。
    2015-06-06
  • Java實(shí)現(xiàn)的計(jì)時(shí)器【秒表】功能示例

    Java實(shí)現(xiàn)的計(jì)時(shí)器【秒表】功能示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的計(jì)時(shí)器【秒表】功能,結(jié)合實(shí)例形式分析了Java結(jié)合JFrame框架的計(jì)時(shí)器功能相關(guān)操作技巧,需要的朋友可以參考下
    2019-02-02
  • mybatis新增save結(jié)束后自動(dòng)返回主鍵id詳解

    mybatis新增save結(jié)束后自動(dòng)返回主鍵id詳解

    這篇文章主要介紹了mybatis新增save結(jié)束后自動(dòng)返回主鍵id詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java中內(nèi)存分配的幾種方法

    Java中內(nèi)存分配的幾種方法

    本文主要介紹Java中幾種分配內(nèi)存的方法。我們會(huì)看到如何使用sun.misc.Unsafe來統(tǒng)一操作任意類型的內(nèi)存。以前用C語言開發(fā)的同學(xué)通常都希望能在Java中通過較底層的接口來操作內(nèi)存,他們一定會(huì)對(duì)本文中要講的內(nèi)容感興趣
    2014-03-03
  • spring boot中內(nèi)嵌redis的使用方法示例

    spring boot中內(nèi)嵌redis的使用方法示例

    這篇文章主要給大家介紹了關(guān)于spring boot中內(nèi)嵌redis使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-06-06
  • IO流概述分類字節(jié)流寫數(shù)據(jù)三種方式及問題分析

    IO流概述分類字節(jié)流寫數(shù)據(jù)三種方式及問題分析

    這篇文章主要為大家介紹了IO流概述分類字節(jié)流寫數(shù)據(jù)三種方式及寫數(shù)據(jù)問題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評(píng)論