httpclient并发性能问题解决

故事

前段时间进行招聘笔试,有这么一个问题,请描述实践过程中解决httpclient并发性能问题的案例。然后自己之前是有遇到过,但是一直没有总结,趁此机会总结一波。

问题

请描述实践过程中解决httpclient并发性能问题的案例。并描述应用场景,问题所在,解决方案。请编写示例代码。

思路

1、使用连接池进行优化
2、并发情况改NIO非阻塞异步调用

未优化直接代码

package ordinary;import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;import java.io.IOException;/*** @author sirwsl* @createTime 2024/4/27 17:05* @version 1.0* @description httpClient正常没有并发情况下使用例子* <p>*     该样例仅作为程序在进行使用HttpClient进行普通调用返回,不会出现并发情况下的简单调用。* </p>*/public class HttpCommonUse {private static final Logger logger = Logger.getLogger(HttpCommonUse.class);public static void main(String[] args) throws IOException {get("https://uapis.cn/api/weather?name=昆明市");post("https://uapis.cn/api/weather?name=昆明市",new StringEntity(""));}public static void get(String url) throws IOException {// 1. 创建HttpClient实例CloseableHttpClient httpClient = HttpClients.createDefault();// 2. 创建GET请求方法实例HttpGet httpGet = new HttpGet(url);// 3. 调用HttpClient实例来执行GET请求方法,得到responseCloseableHttpResponse response = httpClient.execute(httpGet);// 4对得到后的实例可以进行处理,例如读取回复体,读取htmlHttpEntity entity = response.getEntity();//5 执行业务logger.info(EntityUtils.toString(entity));// 6. 释放连接response.close();httpClient.close();}public static void post(String url,HttpEntity entityString) throws IOException {// 1. 创建HttpClient实例CloseableHttpClient httpclient = HttpClients.createDefault();// 2. 创建HttpPost实例HttpPost httpPost = new HttpPost(url);httpPost.setEntity(entityString);// 3. 调用HttpClient实例来执行HttpPost实例CloseableHttpResponse response = httpclient.execute(httpPost);// 4. 读 responseString html = EntityUtils.toString(response.getEntity());logger.info(html);// 5. 释放连接response.close();httpclient.close();}
}

优化后代码

本次优化代码分为1-4个优化样例。请选择适合自己的方式。

httpClient 异步优化
package demo;import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.log4j.Logger;import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import static java.lang.Thread.sleep;/*** @author: sirwsl* @createTime: 2024/4/27 18:12* @version: 1.0* @description: httpClient 异步优化* <p>*     该例子模拟httpClient进行异步调用,本地测试耗时:2500-2900。*     场景:适用于在项目中对同时对第三方服务进行大批量调用,如果不进行异步处理,高并发场景下会出现程序消耗大量资源,*     且等待时间较长。*     程序主要采用CloseableHttpAsyncClient 对httpclient进行整体异步调用,实现NIO实现非阻塞情况。*     通过CloseableHttpAsyncClient 异步策略对原httpClient同步进行整体改善提升效率* </p>*/public class HttpClientAsync {private static final Logger logger = Logger.getLogger(HttpClientAsync.class);public static void main(String[] args) throws IOException, InterruptedException{long start = System.currentTimeMillis();logger.info("请求开始,"+start);CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom().build();int sendTimes = 10;CountDownLatch latch = new CountDownLatch(sendTimes);// 3.发起调用try {// 3.0启动httpclient.start();// 3.1请求参数String url = "https://uapis.cn/api/weather?name=昆明市";for (int i = 0; i < sendTimes; i++) {HttpGet httpget = new HttpGet(url);httpclient.execute(httpget, new FutureCallback<HttpResponse>() {public void failed(final Exception ex) {latch.countDown();logger.error(ex.getLocalizedMessage());}public void completed(final HttpResponse response) {latch.countDown();try {sleep(100);} catch (Exception e) {}}public void cancelled() {latch.countDown();logger.error("取消");}});}} finally {latch.await();httpclient.close();}long end = System.currentTimeMillis();logger.error("请求结束:"+end);logger.error("耗时:"+(end- start));}
}
HttpClient 并发调用
package demo;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;import static java.lang.Thread.sleep;/*** @author: sirwsl* @createTime: 2024/4/27 17:56* @version: 1.0* @description: HttpClient 并发调用* <p>*     该例子中 以10个请求并发,本地测试耗时约在10000-13000左右**     未进行任何优化,以普通方式进行调用,常见于普通项目中,不需要并发前提下可使用该方式*     以该方式调用会出现程序执行效率低,等待时间长等等问题。主要造成该问题是由于HttpClient在进行执行时,重复创建导致,*     一般的每次请求时会初创建一个httpclient,执行httpPost对象或者httpGet对象,然后从返回结果取出entity,最后关闭response释放链接。*     高并发场景下会消耗大量服务器资源。**** </p>*/public class HttpClientDemo {private static final Logger logger = Logger.getLogger(HttpClientDemo.class);public static void main(String[] args) throws InterruptedException, ExecutionException, IOException {long start = System.currentTimeMillis();logger.info("请求开始,"+start);HttpClient httpClient = HttpClients.createDefault();String url = "https://uapis.cn/api/weather?name=昆明市";int sendTimes = 10;ExecutorService executorService = Executors.newFixedThreadPool(sendTimes);List <Future<String>> futures = new ArrayList<>();// 模拟10个httpClient秦秋for (int j = 0; j< sendTimes; j++) {Future<String> future = executorService.submit(() -> {HttpGet httpGet = new HttpGet(url);HttpResponse response = httpClient.execute(httpGet);String responseBody = EntityUtils.toString(response.getEntity());EntityUtils.consume(response.getEntity());return responseBody;});futures.add(future);}for (Future<String> future : futures) {String responseBody = future.get();// 处理业务逻辑sleep(100);}// Shutdown the executor serviceexecutorService.shutdown();long end = System.currentTimeMillis();logger.error("请求结束:"+end);logger.error("耗时:"+(end- start));}}
使用HttpClientBuilder 异步池化方式进行整体并发优化
package demo;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import static java.lang.Thread.sleep;/*** @author: sirwsl* @createTime: 2024/4/27 18:54* @version:* @description: 使用HttpClientBuilder 异步池化方式进行整体并发优化。* <p>*     该例子中 以10个请求并发,本地测试耗时约在110-150左右。*     场景:在进行某些并发程序处理时,由于第三方服务调用并为影响程序主体逻辑执行,可采用CloseableHttpClient+线程池方式进行处理。*     例如某一并发请求调用第三方服务,但需对第三方服务数据进行落库处理,并不会对程序主体逻辑进行改动,此时可通过该方式缩短程序整体响应时间* </p>*/
public class HttpClientPool {private static final Logger logger = Logger.getLogger(HttpClientPool.class);public static void main(String[] args) throws IOException {long start = System.currentTimeMillis();logger.info("请求开始,"+start);// 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(10);// 创建 HttpClient 对象CloseableHttpClient httpClient = HttpClients.createDefault();// 发送 HTTP 请求String url = "https://uapis.cn/api/weather?name=昆明市";for (int i = 0; i < 100; i++) {executorService.execute(() -> {try {HttpClientBuilder httpClientBuilder = HttpClients.custom();httpClientBuilder.setMaxConnTotal(10);httpClientBuilder.setMaxConnPerRoute(10);CloseableHttpClient optimizedHttpClient = httpClientBuilder.build();HttpGet httpGet = new HttpGet(url);CloseableHttpResponse response = httpClient.execute(httpGet);HttpEntity entity = response.getEntity();// 执行业务sleep(100);logger.info(EntityUtils.toString(entity));// 关闭 HttpClientoptimizedHttpClient.close();} catch (Exception e) {e.printStackTrace();}});}// 关闭线程池executorService.shutdown();long end = System.currentTimeMillis();logger.error("请求结束:"+end);logger.error("耗时:"+(end- start));}
}
使用http连接池避免重复开销
package demo;import org.apache.http.HttpEntity;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import java.io.IOException;import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.log4j.Logger;import static java.lang.Thread.sleep;/*** @author: sirwsl* @createTime: 2024/4/27 19:21* @version: 1.0* @description: 使用http连接池避免重复开销* <p>*     该例子中 以10个请求并发,本地测试耗时约在6000-6400左右。*     场景:在并发情况下调用第三方服务,由于HttpClient不主动发起close,链接会维持一段时间*     而该链接又没有进行复用,在维持的时间内,其他并发一进来,服务器会开启大量句炳,当超过上限时,无法建立新的连接,*     此时查看netstart会出现大量的TCP链接处于ESTABLISHED状态。**     在该例子中通过采用CloseableHttpResponse 对httpClient进行池化处理,*     避免httpClient每次new\close的流程对JVM的内存消耗很大,有效避免请求过多句柄不够用情况* </p>*/
public class HttpClientPool2 {private static final Logger logger = Logger.getLogger(demo.HttpClientPool2.class);public static void main(String[] args) throws IOException, InterruptedException {long start = System.currentTimeMillis();logger.info("请求开始,"+start);String url = "https://uapis.cn/api/weather?name=昆明市";int sendTimes = 10;HttpGet httpGet = new HttpGet(url);for (int i = 0; i < sendTimes; i++){CloseableHttpResponse response= HttpClientPool.getHttpClient().execute(httpGet);HttpEntity entity = response.getEntity();//logger.info(EntityUtils.toString(entity));sleep(100);}long end = System.currentTimeMillis();logger.error("请求结束:"+end);logger.error("耗时:"+(end- start));}public static class HttpClientPool {private static PoolingHttpClientConnectionManager cm = null;static {cm = new PoolingHttpClientConnectionManager();cm.setMaxTotal(100);cm.setDefaultMaxPerRoute(10);}public static CloseableHttpClient getHttpClient() {RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();CloseableHttpClient client = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(globalConfig).build();return client;}}}

其他准备

所使用的pom文件

<dependencies><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.2</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.5</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore-nio</artifactId><version>4.4.5</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpasyncclient</artifactId><version>4.1.2</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/34765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业级低代码开发效率变革赋能业务增长

企业级低代码开发已经成为当今软件开发领域的一大趋势&#xff0c;它为企业带来了前所未有的效率变革&#xff0c;从而赋能业务增长。本文将围绕这一主题&#xff0c;深入探讨低代码开发的概念、优势以及如何在企业级应用中实现高效的低代码开发&#xff0c;以助力我国企业实现…

Linux网络 - 再谈、详谈UDP和TCP协议

文章目录 前言预备netstatpidofcat /etc/services 一、UDP协议UDP协议端格式UDP的缓冲区基于UDP的应用层协议 二、TCP协议1.TCP协议段格式确认应答(ACK)机制三次握手疑问1 最后一次客户端发给服务端的ACK请求怎么保证服务端能够收到&#xff1f; 四次挥手疑问2 为什么挥手是四次…

51单片机STC89C52RC——4.1 矩阵按键(数码管显示按键值)

目录 目录 目的 一&#xff0c;STC单片机模块 二&#xff0c;矩阵按键模块 2.1 针脚定义 ​编辑 2.2 矩阵按键位置 2.3 如何理解按键按下后针脚的高低电平 2.3.1 错误理解1 2.3.2 错误理解2 2.3.3 正确判定按下的是那个按键的逻辑 2.3.4 判定按键按下的依次扫描程…

2024年618有哪些必囤的好物?2024年618好物排行榜

618年中大促再度来临。对于购物爱好者来说&#xff0c;这无疑是一个不容错过的购物盛宴。那么&#xff0c;在这个618&#xff0c;哪些好物值得你重点关注呢&#xff1f;我特地整理了一份推荐清单&#xff0c;这些产品不仅经过我的亲身体验&#xff0c;更以其出色的实用性和高性…

MySQL中结构化系统变量介绍

结构化变量&#xff08;structured variable&#xff09;与常规系统变量&#xff08;regular system variable&#xff09;之间的两个主要区别。以下是这两个区别的详细解释&#xff1a; 值是一个结构&#xff1a; 常规系统变量通常存储单一的值&#xff0c;比如一个整数、浮…

【XCharts插件】4-2、配置项手册(v3.0)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群:398291828大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 XCharts插件是一款基于UGUI的功能强大、易用、参数可配置的数据可视化图表插件。 【Unity3D…

硬件基础知识——自学习梳理

计算机存储分为闪存和永久性存储。 硬盘&#xff08;永久存储&#xff09;主要分为机械磁盘和固态硬盘。 机械磁盘主要靠磁颗粒的正负极方向来存储0或1&#xff0c;且机械磁盘没有使用寿命。 固态硬盘就有使用寿命了&#xff0c;大概支持30w次的读写操作。 闪存使用的是电容…

使用js实现excel的读取展示以及导出

代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><link rel"st…

liunx打开谷歌报错

liunx打开谷歌报错[48526:48526:0624/173553.311113:ERROR:zygote_host_impl_linux.cc(99)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180. 这个错误信息表明你尝试以root用户身份运行Chrome浏览器&#xff0c;但是没有使用–no-san…

现身说法,AI小白的大模型学习过程

导读 写这篇文章的初衷&#xff1a;作为一个AI小白&#xff0c;把我自己学习大模型的学习路径还原出来&#xff0c;包括理解的逻辑、看到的比较好的学习材料&#xff0c;通过一篇文章给串起来&#xff0c;对大模型建立起一个相对体系化的认知&#xff0c;才能够在扑面而来的大…

idea 突然 Cannot resolve symbol ‘xxx‘

解决一&#xff1a;关闭 idea&#xff0c;在文件夹中找到代码所在位置&#xff0c;删除 .idea 文件夹重新打开项目就可以了 解决二&#xff1a;检查 jdk 版本 解决三&#xff1a;保存重要文件&#xff0c;重新下载项目代码

接口防篡改+防重放攻击

接口防止重放攻击&#xff1a;重放攻击是指攻击者截获了一次有效请求(如交易请求),并在之后的时间里多次发送相同的请求&#xff0c;从而达到欺骗系统的目的。为了防止重放攻击&#xff0c;通常需要在系统中引入一种机制&#xff0c;使得每个请求都有一个唯一的标识符(如时间戳…

深度学习训练基于Pod和RDMA

目录 ​编辑 引言 RDMA技术概述 InfiniBand iWARP RoCE Pod和容器化环境 深度学习训练与RDMA结合 MPI和RDMA 深度学习框架与RDMA 实战&#xff1a;基于Pod和RDMA的深度学习训练 环境准备 步骤 YAML 性能和优势 结论 引言 随着深度学习在人工智能领域的快速发展…

Linux下命令行文件创建删除、目录创建删除

在Linux命令行下&#xff0c;文件和目录的创建与删除是通过一系列基础命令完成的&#xff0c;这些命令对于日常的系统管理和文件操作至关重要。 下面将详细介绍这些命令的功能和使用方法。 普通文件的创建与删除 创建文件 touch命令&#xff1a;主要用于创建一个空文件&…

使用Tauri+vite+koa2+mysql开发了一款待办效率应用

&#x1f389;使用Taurivitekoa2mysql开发了一款待办效率应用 &#x1f4dd;项目概述 这是一个基于taurivite的应用&#xff0c;它采用了一些最新的前端技术&#xff0c;包括 Tauri、Vue3、Vite5、koa2 和 mysql。它提供了丰富的效率管理工具。 应用地址&#xff1a;https:/…

Laravel依赖注入全解析:构建灵活应用的秘诀

Laravel依赖注入全解析&#xff1a;构建灵活应用的秘诀 引言 Laravel框架以其优雅的语法和强大的功能著称&#xff0c;其中依赖注入&#xff08;Dependency Injection&#xff09;是其核心特性之一。依赖注入是一种设计模式&#xff0c;用于减少代码间的耦合度&#xff0c;提…

Openldap安装部署及Gitea简单配置使用

Openldap安装部署及Gitea简单配置使用 一.安装Openldap #拉取镜像 docker pull osixia/openldap:latestdocker run \ -d \ -p 389:389 \ -p 636:636 \ -v /home/data/openldap/local:/usr/local/ldap \ -v /home/data/openldap/lib:/var/lib/ldap \ -v /home/data/openldap/s…

OceanBase 列存中多列过滤性能解析

今天有同事问我&#xff0c;列存大宽表场景下&#xff0c;如果在多个列上有等值过滤条件&#xff0c;OceanBase 的性能是不是无法满足要求&#xff1f; Hi 晓楚&#xff0c;帮评估个OTS替换场景 大概1亿大宽表&#xff0c;查询姿势就是任意字段的组合&#xff0c;进行等值查询g…

海外青云私有云:企业的数字化转型得力助手

在全球化日益加深的今天&#xff0c;海外企业对于云计算的需求也愈发迫切。青云(QingCloud)作为一家领先的云计算服务提供商&#xff0c;其私有云产品在海外市场上受到了广泛的关注和认可。那么&#xff0c;海外青云私有云究竟有何用处呢?本文将从多个角度为您科普。 首先&…

Java高级重点知识点-10-Object类

文章目录 Object类(java.lang) Object类(java.lang) Object类是Java语言中的根类&#xff0c;即所有类的父类 重点&#xff1a; public String toString()&#xff1a;返回该对象的字符串表示。 public class User {private String username;private String password;public…