java-httpasyncclient使用记录

这是几年前写的旧文,此前发布Wordpress小站上,现在又重新整理。算是温故知新,后续会继续整理。如有错误望及时指出,在此感谢。

随着线上业务量不断增加,会对原来的技术框架带来不小的挑战,这里记录一次线上HTTP服务调优的过程。

业务场景描述

产品A

提供了一个http接口服务,用来处理数据请求;

产品B

小菜,按照产品A的接口要求,把数据发送给产品A的接口服务处理;

....................

小菜:这个我熟,httpclient大法,走你...

public static int post(final String url, final Header[] headers, final HttpEntity entiry) throws IOException {
    int statusCode = -1;
    HttpResponse httpResponse = null;
    try {
        if (httpPost == null || httpPost.isAborted()) {
            httpPost = new HttpPost(url);
        }

        if (headers != null && headers.length > 0) {
            httpPost.setHeaders(headers);
        }

        if (entiry != null) {
            httpPost.setEntity(entiry);
            
            httpResponse = httpClient.execute(httpPost);
    
            if (Objects.nonNull(httpResponse)) {
                HttpEntity httpEntity = httpResponse.getEntity();
                statusCode = httpResponse.getStatusLine().getStatusCode();
                
                return statusCode;
            } else {
                return -1;
            }
        }else{
            return -1;
        }
    } catch (Exception e) {
        logger.error("http post error", e);
        throw e;
    } finally {
        if (httpResponse != null) {
            EntityUtils.consumeQuietly(httpResponse.getEntity());
        }
    }

}

收工.走人....

....................................

(三个月后.....)

boss:小菜呀,现在业务量越来越大啦,数据处理不过来,你赶紧处理下....

小菜:没问题....

(白天....)

小菜:(我擦咧)数据量增加十倍不止,加线程,加并发,快,快...

(半夜....)

小菜:杂回事,不好使啊.赶紧翻翻httpclient文档.

小菜:(Pooling connection manager,嗯,连接池,安排,安排上...)

小菜:(咦,下面的HttpAsyncClient,这是什么东东...)

img

(老师说过,名字越长的越厉害,HttpClient VS HttpAsyncClient)那肯定后者更厉害,那就了解下...)

HttpAsyncClient may be of interest to anyone building HTTP-aware client applications based on asynchronous, event driven I/O model.

通过官网的描述,小菜了解到,原来HttpAsyncClient是对原来HttpClient的扩展,基于异步事件驱动的。总结下来就是性能更好,支持高并发场景。

等等,这不就是小菜正在找的嘛?

说干就干。

首先,HttpAsyncClient和HttpClient一样,都是线程安全的,所以在多线程情况下可以放心使用。

这是官网的例子:

CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
try {
    // Start the client
    httpclient.start();

    // Execute request
    final HttpGet request1 = new HttpGet("http://www.apache.org/");
    Future<HttpResponse> future = httpclient.execute(request1, null);
    // and wait until a response is received
    HttpResponse response1 = future.get();
    System.out.println(request1.getRequestLine() + "->" + response1.getStatusLine());

    // One most likely would want to use a callback for operation result
    final CountDownLatch latch1 = new CountDownLatch(1);
    final HttpGet request2 = new HttpGet("http://www.apache.org/");
    httpclient.execute(request2, new FutureCallback<HttpResponse>() {

        public void completed(final HttpResponse response2) {
            latch1.countDown();
            System.out.println(request2.getRequestLine() + "->" + response2.getStatusLine());
        }

        public void failed(final Exception ex) {
            latch1.countDown();
            System.out.println(request2.getRequestLine() + "->" + ex);
        }

        public void cancelled() {
            latch1.countDown();
            System.out.println(request2.getRequestLine() + " cancelled");
        }

    });
    latch1.await();

    // In real world one most likely would also want to stream
    // request and response body content
    final CountDownLatch latch2 = new CountDownLatch(1);
    final HttpGet request3 = new HttpGet("http://www.apache.org/");
    HttpAsyncRequestProducer producer3 = HttpAsyncMethods.create(request3);
    AsyncCharConsumer<HttpResponse> consumer3 = new AsyncCharConsumer<HttpResponse>() {

        HttpResponse response;

        @Override
        protected void onResponseReceived(final HttpResponse response) {
            this.response = response;
        }

        @Override
        protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
            // Do something useful
        }

        @Override
        protected void releaseResources() {
        }

        @Override
        protected HttpResponse buildResult(final HttpContext context) {
            return this.response;
        }

    };
    httpclient.execute(producer3, consumer3, new FutureCallback<HttpResponse>() {

        public void completed(final HttpResponse response3) {
            latch2.countDown();
            System.out.println(request3.getRequestLine() + "->" + response3.getStatusLine());
        }

        public void failed(final Exception ex) {
            latch2.countDown();
            System.out.println(request3.getRequestLine() + "->" + ex);
        }

        public void cancelled() {
            latch2.countDown();
            System.out.println(request3.getRequestLine() + " cancelled");
        }

    });
    latch2.await();} finally {
    httpclient.close();
}

在实际项目中,我们会是多进程多线程场景,这块的使用我这里就多重复了,有其它网友比我总结的更好,这里只针对在高并发场景下,HttpClient VS HttpAsyncClient的性能做一次测试。

说下结论,不进行参数优化的场景下,HttpClient,单线程QPS能在80-100qps/s。

而HttpAsyncClient不进行参数优化的场景下,单线程QPS能在1000-1200qps/s。

优化部分参数后,参稳定在1300qps/s。

好啦,小菜把代码优化以后,重新部署后,数据积压问题解决了。

睡觉喽。

posted @   畔山陆仁贾  阅读(391)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示