国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

高并發(fā)場景下的 HttpClient 優(yōu)化,QPS 大大提升!

這篇具有很好參考價值的文章主要介紹了高并發(fā)場景下的 HttpClient 優(yōu)化,QPS 大大提升!。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

HttpClient優(yōu)化思路:

  1. 池化
  2. 長連接
  3. httpclient和httpget復(fù)用
  4. 合理的配置參數(shù)(最大并發(fā)請求數(shù),各種超時時間,重試次數(shù))
  5. 異步 6、多讀源碼

1.背景

我們有個業(yè)務(wù),會調(diào)用其他部門提供的一個基于http的服務(wù),日調(diào)用量在千萬級別。使用了httpclient來完成業(yè)務(wù)。之前因為qps上不去,就看了一下業(yè)務(wù)代碼,并做了一些優(yōu)化,記錄在這里。

先對比前后:優(yōu)化之前,平均執(zhí)行時間是250ms;優(yōu)化之后,平均執(zhí)行時間是80ms,降低了三分之二的消耗,容器不再動不動就報警線程耗盡了,清爽~

2.分析

項目的原實現(xiàn)比較粗略,就是每次請求時初始化一個httpclient,生成一個httpPost對象,執(zhí)行,然后從返回結(jié)果取出entity,保存成一個字符串,最后顯式關(guān)閉response和client。我們一點點分析和優(yōu)化:

2.1 httpclient反復(fù)創(chuàng)建開銷

httpclient是一個線程安全的類,沒有必要由每個線程在每次使用時創(chuàng)建,全局保留一個即可。

2.2 反復(fù)創(chuàng)建tcp連接的開銷

tcp的三次握手與四次揮手兩大裹腳布過程,對于高頻次的請求來說,消耗實在太大。試想如果每次請求我們需要花費5ms用于協(xié)商過程,那么對于qps為100的單系統(tǒng),1秒鐘我們就要花500ms用于握手和揮手。又不是高級領(lǐng)導(dǎo),我們程序員就不要搞這么大做派了,改成keep alive方式以實現(xiàn)連接復(fù)用!

2.3 重復(fù)緩存entity的開銷

原本的邏輯里,使用了如下代碼:

HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity);

這里我們相當(dāng)于額外復(fù)制了一份content到一個字符串里,而原本的httpResponse仍然保留了一份content,需要被consume掉,在高并發(fā)且content非常大的情況下,會消耗大量內(nèi)存。并且,我們需要顯式的關(guān)閉連接,ugly。

3.實現(xiàn)

按上面的分析,我們主要要做三件事:一是單例的client,二是緩存的?;钸B接,三是更好的處理返回結(jié)果。一就不說了,來說說二。

提到連接緩存,很容易聯(lián)想到數(shù)據(jù)庫連接池。httpclient4提供了一個PoolingHttpClientConnectionManager 作為連接池。接下來我們通過以下步驟來優(yōu)化:

3.1 定義一個keep alive strategy

關(guān)于keep-alive,本文不展開說明,只提一點,是否使用keep-alive要根據(jù)業(yè)務(wù)情況來定,它并不是靈丹妙藥。還有一點,keep-alive和time_wait/close_wait之間也有不少故事。

在本業(yè)務(wù)場景里,我們相當(dāng)于有少數(shù)固定客戶端,長時間極高頻次的訪問服務(wù)器,啟用keep-alive非常合適

再多提一嘴,http的keep-alive 和tcp的KEEPALIVE不是一個東西。回到正文,定義一個strategy如下:

ConnectionKeepAliveStrategy myStrategy = 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")) {
                return Long.parseLong(value) * 1000;
            }
        }
        return 60 * 1000;//如果沒有約定,則默認(rèn)定義時長為60s
    }
};

3.2 配置一個PoolingHttpClientConnectionManager

PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(500);
connectionManager.setDefaultMaxPerRoute(50);//例如默認(rèn)每路由最高50并發(fā),具體依據(jù)業(yè)務(wù)來定

也可以針對每個路由設(shè)置并發(fā)數(shù)。

3.3 生成httpclient

httpClient = HttpClients.custom()
    .setConnectionManager(connectionManager)
    .setKeepAliveStrategy(kaStrategy)
    .setDefaultRequestConfig(RequestConfig.custom().setStaleConnectionCheckEnabled(true).build())
    .build();

注意:使用setStaleConnectionCheckEnabled方法來逐出已被關(guān)閉的鏈接不被推薦。更好的方式是手動啟用一個線程,定時運行closeExpiredConnections 和closeIdleConnections方法,如下所示。

public static class IdleConnectionMonitorThread extends Thread {
    
    private final HttpClientConnectionManager connMgr;
    private volatile boolean shutdown;
    
    public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
        super();
        this.connMgr = connMgr;
    }
 
    @Override
    public void run() {
        try {
            while (!shutdown) {
                synchronized (this) {
                    wait(5000);
                    // Close expired connections
                    connMgr.closeExpiredConnections();
                    // Optionally, close connections
                    // that have been idle longer than 30 sec
                    connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
                }
            }
        } catch (InterruptedException ex) {
            // terminate
        }
    }
    
    public void shutdown() {
        shutdown = true;
        synchronized (this) {
            notifyAll();
        }
    }
    
}

3.4 使用httpclient執(zhí)行method時降低開銷

這里要注意的是,不要關(guān)閉connection。

一種可行的獲取內(nèi)容的方式類似于,把entity里的東西復(fù)制一份:

res = EntityUtils.toString(response.getEntity(),"UTF-8");
EntityUtils.consume(response1.getEntity());

但是,更推薦的方式是定義一個ResponseHandler,方便你我他,不再自己catch異常和關(guān)閉流。在此我們可以看一下相關(guān)的源碼:

public <T> T execute(final HttpHost target, final HttpRequest request,
            final ResponseHandler<? extends T> responseHandler, final HttpContext context)
            throws IOException, ClientProtocolException {
        Args.notNull(responseHandler, "Response handler");
 
        final HttpResponse response = execute(target, request, context);
 
        final T result;
        try {
            result = responseHandler.handleResponse(response);
        } catch (final Exception t) {
            final HttpEntity entity = response.getEntity();
            try {
                EntityUtils.consume(entity);
            } catch (final Exception t2) {
                // Log this exception. The original exception is more
                // important and will be thrown to the caller.
                this.log.warn("Error consuming content after an exception.", t2);
            }
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            }
            if (t instanceof IOException) {
                throw (IOException) t;
            }
            throw new UndeclaredThrowableException(t);
        }
 
        // Handling the response was successful. Ensure that the content has
        // been fully consumed.
        final HttpEntity entity = response.getEntity();
        EntityUtils.consume(entity);//看這里看這里
        return result;
    }

可以看到,如果我們使用resultHandler執(zhí)行execute方法,會最終自動調(diào)用consume方法,而這個consume方法如下所示:

public static void consume(final HttpEntity entity) throws IOException {
        if (entity == null) {
            return;
        }
        if (entity.isStreaming()) {
            final InputStream instream = entity.getContent();
            if (instream != null) {
                instream.close();
            }
        }
    }

可以看到最終它關(guān)閉了輸入流。

4.其他

通過以上步驟,基本就完成了一個支持高并發(fā)的httpclient的寫法,下面是一些額外的配置和提醒:

4.1 httpclient的一些超時配置

CONNECTION_TIMEOUT是連接超時時間,SO_TIMEOUT是socket超時時間,這兩者是不同的。連接超時時間是發(fā)起請求前的等待時間;socket超時時間是等待數(shù)據(jù)的超時時間。

HttpParams params = new BasicHttpParams();
//設(shè)置連接超時時間
Integer CONNECTION_TIMEOUT = 2 * 1000; //設(shè)置請求超時2秒鐘 根據(jù)業(yè)務(wù)調(diào)整
Integer SO_TIMEOUT = 2 * 1000; //設(shè)置等待數(shù)據(jù)超時時間2秒鐘 根據(jù)業(yè)務(wù)調(diào)整
 
//定義了當(dāng)從ClientConnectionManager中檢索ManagedClientConnection實例時使用的毫秒級的超時時間
//這個參數(shù)期望得到一個java.lang.Long類型的值。如果這個參數(shù)沒有被設(shè)置,默認(rèn)等于CONNECTION_TIMEOUT,因此一定要設(shè)置。
Long CONN_MANAGER_TIMEOUT = 500L; //在httpclient4.2.3中我記得它被改成了一個對象導(dǎo)致直接用long會報錯,后來又改回來了
 
params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, CONNECTION_TIMEOUT);
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SO_TIMEOUT);
params.setLongParameter(ClientPNames.CONN_MANAGER_TIMEOUT, CONN_MANAGER_TIMEOUT);
//在提交請求之前 測試連接是否可用
params.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, true);
 
//另外設(shè)置http client的重試次數(shù),默認(rèn)是3次;當(dāng)前是禁用掉(如果項目量不到,這個默認(rèn)即可)
httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));

4.2 如果配置了nginx的話,nginx也要設(shè)置面向兩端的keep-alive

現(xiàn)在的業(yè)務(wù)里,沒有nginx的情況反而比較稀少。nginx默認(rèn)和client端打開長連接而和server端使用短鏈接。注意client端的keepalive_timeout和keepalive_requests參數(shù),以及upstream端的keepalive參數(shù)設(shè)置,這三個參數(shù)的意義在此也不再贅述。

以上就是我的全部設(shè)置。通過這些設(shè)置,成功地將原本每次請求250ms的耗時降低到了80左右,效果顯著。

JAR包如下:

<!-- httpclient -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.6</version>
</dependency>

代碼如下:

//Basic認(rèn)證
private static final CredentialsProvider credsProvider = new BasicCredentialsProvider();
//httpClient
private static final CloseableHttpClient httpclient;
//httpGet方法
private static final HttpGet httpget;
//
private static final RequestConfig reqestConfig;
//響應(yīng)處理器
private static final ResponseHandler<String> responseHandler;
//jackson解析工具
private static final ObjectMapper mapper = new ObjectMapper();
static {
    System.setProperty("http.maxConnections","50");
    System.setProperty("http.keepAlive", "true");
    //設(shè)置basic校驗
    credsProvider.setCredentials(
            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM),
            new UsernamePasswordCredentials("", ""));
    //創(chuàng)建http客戶端
    httpclient = HttpClients.custom()
            .useSystemProperties()
            .setRetryHandler(new DefaultHttpRequestRetryHandler(3,true))
            .setDefaultCredentialsProvider(credsProvider)
            .build();
    //初始化httpGet
    httpget = new HttpGet();
    //初始化HTTP請求配置
    reqestConfig = RequestConfig.custom()
            .setContentCompressionEnabled(true)
            .setSocketTimeout(100)
            .setAuthenticationEnabled(true)
            .setConnectionRequestTimeout(100)
            .setConnectTimeout(100).build();
    httpget.setConfig(reqestConfig);
    //初始化response解析器
    responseHandler = new BasicResponseHandler();
}
/*
 * 功能:返回響應(yīng)
 * @author zhangdaquan
 * @date 2019/1/3 上午11:19
 * @param [url]
 * @return org.apache.http.client.methods.CloseableHttpResponse
 * @exception
 */
public static String getResponse(String url) throws IOException {
    HttpGet get = new HttpGet(url);
    String response = httpclient.execute(get,responseHandler);
    return response;
}
 
/*
 * 功能:發(fā)送http請求,并用net.sf.json工具解析
 * @author zhangdaquan
 * @date 2018/8/15 下午2:21
 * @param [url]
 * @return org.json.JSONObject
 * @exception
 */
public static JSONObject getUrl(String url) throws Exception{
    try {
        httpget.setURI(URI.create(url));
        String response = httpclient.execute(httpget,responseHandler);
        JSONObject json = JSONObject.fromObject(response);
        return json;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
/*
 * 功能:發(fā)送http請求,并用jackson工具解析
 * @author zhangdaquan
 * @date 2018/12/24 下午2:58
 * @param [url]
 * @return com.fasterxml.jackson.databind.JsonNode
 * @exception
 */
public static JsonNode getUrl2(String url){
    try {
        httpget.setURI(URI.create(url));
        String response = httpclient.execute(httpget,responseHandler);
        JsonNode node = mapper.readTree(response);
        return node;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
/*
 * 功能:發(fā)送http請求,并用fastjson工具解析
 * @author zhangdaquan
 * @date 2018/12/24 下午2:58
 * @param [url]
 * @return com.fasterxml.jackson.databind.JsonNode
 * @exception
 */
public static com.alibaba.fastjson.JSONObject getUrl3(String url){
    try {
        httpget.setURI(URI.create(url));
        String response = httpclient.execute(httpget,responseHandler);
        com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(response);
        return jsonObject;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

原文:blog.csdn.net/u010285974/article/details/85696239

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協(xié)程要來了。。。

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優(yōu)雅的方式!!

5.《Java開發(fā)手冊(嵩山版)》最新發(fā)布,速速下載!

覺得不錯,別忘了隨手點贊+轉(zhuǎn)發(fā)哦!文章來源地址http://www.zghlxwxcb.cn/news/detail-436290.html

到了這里,關(guān)于高并發(fā)場景下的 HttpClient 優(yōu)化,QPS 大大提升!的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 設(shè)計模式之并發(fā)特定場景下的設(shè)計模式 Two-phase Termination(兩階段終止)模式

    在線程1中如何終止線程2? stop()?還是System.exit()?還是其他方式 1.使用stop()不可取 線程對象的stop()方法會直接殺死線程,假設(shè)此時使用了線程鎖,當(dāng)此時使用了stop()命令會導(dǎo)致線程鎖無法釋放,以至于程序出現(xiàn)嚴(yán)重的問題,其中最常見的是死鎖。還可能導(dǎo)致資源泄露,因為

    2024年01月21日
    瀏覽(22)
  • GCS軌跡優(yōu)化算法:有效提升機(jī)器人在復(fù)雜環(huán)境下的行動能力

    GCS軌跡優(yōu)化算法:有效提升機(jī)器人在復(fù)雜環(huán)境下的行動能力

    原創(chuàng) | 文 BFT機(jī)器人? 機(jī)器人要在迷宮中找到出路并非易事,試想我們讓機(jī)器人穿越一個孩子的游戲室,散落在地板上的各種玩具和各類家具擋住了一些潛在的路徑。這個混亂的”迷宮“要求機(jī)器人在不與任何障礙物相撞的情況下計算到達(dá)目的地的最優(yōu)路徑,機(jī)器人該怎么做呢

    2024年02月04日
    瀏覽(22)
  • 火山引擎在行為分析場景下的ClickHouse JOIN優(yōu)化

    火山引擎在行為分析場景下的ClickHouse JOIN優(yōu)化

    更多技術(shù)交流、求職機(jī)會,歡迎關(guān)注 字節(jié)跳動數(shù)據(jù)平臺微信公眾號,回復(fù)【1】進(jìn)入官方交流群 火山引擎增長分析DataFinder基于ClickHouse來進(jìn)行行為日志的分析,ClickHouse的主要版本是基于社區(qū)版改進(jìn)開發(fā)的字節(jié)內(nèi)部版本。主要的表結(jié)構(gòu): ? 事件表:存儲用戶行為數(shù)據(jù),以 用戶

    2023年04月26日
    瀏覽(18)
  • Unity3D:提升場景畫面品質(zhì)&平衡性能優(yōu)化

    Unity3D:提升場景畫面品質(zhì)&平衡性能優(yōu)化

    在日常開發(fā)中,提升場景畫面品質(zhì)的同時平衡性能優(yōu)化一直是很重要且頭疼的一部分,尤其是當(dāng)場景類型不同及效果需求不一樣時。 所以怎么同時提升場景畫面品質(zhì)和平衡性能優(yōu)化呢,下面介紹一些適用度高且實用性好的設(shè)置。 介紹之前先說一下結(jié)論:怎么樣才能說的上是

    2024年02月08日
    瀏覽(95)
  • QPS、TPS、RT、并發(fā)用戶數(shù)、吞吐量

    QPS QPS Queries Per Second 是每秒查詢率 ,是 一臺服務(wù)器 每秒能夠相應(yīng)的查詢次數(shù),是對一個特定的查詢服務(wù)器 在規(guī)定時間內(nèi) 所處理流量多少的衡量標(biāo)準(zhǔn), 即每秒的響應(yīng)請求數(shù),也即是最大吞吐能力。 TPS TPS Transactions Per Second 也就是事務(wù)數(shù)/秒。一個事務(wù)是指一個客戶機(jī)向服務(wù)器發(fā)

    2024年02月05日
    瀏覽(24)
  • midjourney ai與ChatGPT結(jié)合使用,大大提升返回結(jié)果準(zhǔn)確率

    midjourney ai與ChatGPT結(jié)合使用,大大提升返回結(jié)果準(zhǔn)確率

    最近在試用midjourney ai繪圖,結(jié)合ChatGPT給到更多的特征來說明 如果只是單純的提問,可能返回雜亂的圖片. 提問時要把相關(guān)特征,風(fēng)格,物件都要說清楚,ai才能識別得到,放幾張體驗照: 生成結(jié)束后將會出現(xiàn)兩排按鈕。 U是upscale的縮寫,含義為放大像素提升細(xì)節(jié),U1, U2, U3,

    2023年04月19日
    瀏覽(19)
  • 騰訊云V265/TXAV1直播場景下的編碼優(yōu)化和應(yīng)用

    騰訊云V265/TXAV1直播場景下的編碼優(yōu)化和應(yīng)用

    ? //?? 編者按:隨著視頻直播不斷向著超高清、低延時、高碼率的方向發(fā)展, Apple Vision的出現(xiàn)又進(jìn)一步拓展了對3D, 8K 120FPS的視頻編碼需求,視頻的編碼優(yōu)化也變得越來越具有挑戰(zhàn)性。LiveVideoStackCon 2023上海站邀請到騰訊云的姜驁杰老師分享騰訊云V265/TXAV1直播場景下的編碼優(yōu)

    2024年02月11日
    瀏覽(22)
  • 【Redis】電商項目秒殺問題之下單接口優(yōu)化:Redis緩存、MQ以及l(fā)ua腳本優(yōu)化高并發(fā)背景下的秒殺下單問題

    【Redis】電商項目秒殺問題之下單接口優(yōu)化:Redis緩存、MQ以及l(fā)ua腳本優(yōu)化高并發(fā)背景下的秒殺下單問題

    目錄 一、優(yōu)化思路 二、緩存庫存與訂單 1、庫存緩存的redis數(shù)據(jù)結(jié)構(gòu) 2、訂單信息緩存的redis數(shù)據(jù)結(jié)構(gòu) 三、整體流程 四、lua腳本確保權(quán)限校驗操作的原子性 【Redis】電商項目秒殺問題之超賣問題與一人一單問題_1373i的博客-CSDN博客 https://blog.csdn.net/qq_61903414/article/details/1305689

    2024年02月05日
    瀏覽(19)
  • 高并發(fā)場景下大量TCP鏈接處于time_wait狀態(tài)原因及優(yōu)化思路分析

    高并發(fā)場景下大量TCP鏈接處于time_wait狀態(tài)原因及優(yōu)化思路分析

    對一臺服務(wù)器進(jìn)行壓測(模擬高并發(fā)場景),會發(fā)現(xiàn)大量 TIME_WAIT 狀態(tài)的 TCP連接,連接關(guān)閉后,這些TIME_WAIT會被系統(tǒng)回收 一般來講,在高并發(fā)的場景中,出現(xiàn)TIME_WAIT連接是正?,F(xiàn)象,一旦四次握手連接關(guān)閉之后,這些連接也就隨之被系統(tǒng)回收了 但是在實際高并發(fā)場景中,很

    2024年02月04日
    瀏覽(37)
  • 自動彈性,QPS線性提升|一文讀懂云原生數(shù)倉AnalyticDB彈性技術(shù)原理

    自動彈性,QPS線性提升|一文讀懂云原生數(shù)倉AnalyticDB彈性技術(shù)原理

    在全球經(jīng)濟(jì)增長放緩的大背景之下,企業(yè)在加強(qiáng)數(shù)字化建設(shè)的過程中,實現(xiàn)效益最大化成為一個繞不開的話題。阿里云瑤池旗下的 云原生數(shù)倉AnalyticDB?MySQL湖倉版 (以下簡稱AnalyticDB?MySQL)在發(fā)布之初提供了定時彈性功能,幫助業(yè)務(wù)有規(guī)律的客戶定時升降配計算資源以節(jié)省成

    2024年02月19日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包