当前位置: 首页 > news >正文

天德建设集团网站莆田人做的网站

天德建设集团网站,莆田人做的网站,谷歌推广运营,快乐无极网站HttpClient优化思路 使用连接池#xff08;简单粗暴#xff09; 长连接优化#xff08;特殊业务场景#xff09; httpclient和httpget复用 合理的配置参数#xff08;最大并发请求数#xff0c;各种超时时间#xff0c;重试次数#xff09; 异步请求优化#xff0…HttpClient优化思路 使用连接池简单粗暴 长连接优化特殊业务场景 httpclient和httpget复用 合理的配置参数最大并发请求数各种超时时间重试次数 异步请求优化并发 1.背景 假设有一个http的服务日调用量在千万级别。使用了httpclient来完成业务但qps上不去性能不佳需要优化。 优化之前平均执行时间是250ms 优化之后平均执行时间是80ms降低了三分之二的消耗。 2.分析 项目的原实现比较粗略就是每次请求时初始化一个httpclient生成一个httpPost对象执行然后从返回结果取出entity保存成一个字符串最后显式关闭response和client。 我们一点点分析和优化 2.1 httpclient反复创建开销 httpclient是一个线程安全的类没有必要由每个线程在每次使用时创建全局保留一个即可。 2.2 反复创建tcp连接的开销 tcp的三次握手与四次挥手两大裹脚布过程对于高频次的请求来说消耗实在太大。试想如果每次请求我们需要花费5ms用于协商过程那么对于qps为100的单系统1秒钟我们就要花500ms用于握手和挥手。又不是高级领导我们程序员就不要搞这么大做派了改成keep alive方式以实现连接复用 2.3 重复缓存entity的开销 原本的逻辑里使用了如下代码 HttpEntity entity  httpResponse.getEntity();String response  EntityUtils.toString(entity);这里我们相当于额外复制了一份content到一个字符串里而原本的httpResponse仍然保留了一份content需要被consume掉在高并发且content非常大的情况下会消耗大量内存。并且我们需要显式的关闭连接ugly。 3.实现 按上面的分析我们主要要做三件事一是单例的client二是缓存的保活连接三是更好的处理返回结果。一就不说了来说说二。 提到连接缓存很容易联想到数据库连接池。httpclient4提供了一个PoolingHttpClientConnectionManager 作为连接池。接下来我们通过以下步骤来优化 3.1 定义一个keep alive strategy 关于keep-alive本文不展开说明只提一点是否使用keep-alive要根据业务情况来定它并不是灵丹妙药。还有一点keep-alive和time_wait/close_wait之间也有不少故事。 在本业务场景里我们相当于有少数固定客户端长时间极高频次的访问服务器启用keep-alive非常合适 再多提一嘴http的keep-alive 和tcp的KEEPALIVE不是一个东西。回到正文定义一个strategy如下 ConnectionKeepAliveStrategy myStrategy  new ConnectionKeepAliveStrategy() {Overridepublic 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;//如果没有约定则默认定义时长为60s} };3.2 配置一个PoolingHttpClientConnectionManager PoolingHttpClientConnectionManager connectionManager  new PoolingHttpClientConnectionManager(); connectionManager.setMaxTotal(500); connectionManager.setDefaultMaxPerRoute(50);//例如默认每路由最高50并发具体依据业务来定也可以针对每个路由设置并发数。 3.3 生成httpclient httpClient  HttpClients.custom().setConnectionManager(connectionManager).setKeepAliveStrategy(kaStrategy).setDefaultRequestConfig(RequestConfig.custom().setStaleConnectionCheckEnabled(true).build()).build();❝ 注意使用setStaleConnectionCheckEnabled方法来逐出已被关闭的链接不被推荐。更好的方式是手动启用一个线程定时运行closeExpiredConnections 和closeIdleConnections方法如下所示。 ❞ public static class IdleConnectionMonitorThread extends Thread {private final HttpClientConnectionManager connMgr;private volatile boolean shutdown;public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {super();this.connMgr  connMgr;}Overridepublic void run() {try {while (!shutdown) {synchronized (this) {wait(5000);// Close expired connectionsconnMgr.closeExpiredConnections();// Optionally, close connections// that have been idle longer than 30 secconnMgr.closeIdleConnections(30, TimeUnit.SECONDS);}}} catch (InterruptedException ex) {// terminate}}public void shutdown() {shutdown  true;synchronized (this) {notifyAll();}}}3.4 使用httpclient执行method时降低开销 ❝ 这里要注意的是不要关闭connection。 ❞ 一种可行的获取内容的方式类似于把entity里的东西复制一份 res  EntityUtils.toString(response.getEntity(),UTF-8); EntityUtils.consume(response1.getEntity());但是更推荐的方式是定义一个ResponseHandler方便你我他不再自己catch异常和关闭流。在此我们可以看一下相关的源码 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执行execute方法会最终自动调用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();}} }可以看到最终它关闭了输入流。 4.其他 通过以上步骤基本就完成了一个支持高并发的httpclient的写法下面是一些额外的配置和提醒 4.1 httpclient的一些超时配置 CONNECTION_TIMEOUT是连接超时时间SO_TIMEOUT是socket超时时间这两者是不同的。连接超时时间是发起请求前的等待时间socket超时时间是等待数据的超时时间。 HttpParams params  new BasicHttpParams(); //设置连接超时时间 Integer CONNECTION_TIMEOUT  2 * 1000; //设置请求超时2秒钟 根据业务调整 Integer SO_TIMEOUT  2 * 1000; //设置等待数据超时时间2秒钟 根据业务调整//定义了当从ClientConnectionManager中检索ManagedClientConnection实例时使用的毫秒级的超时时间 //这个参数期望得到一个java.lang.Long类型的值。如果这个参数没有被设置默认等于CONNECTION_TIMEOUT因此一定要设置。 Long CONN_MANAGER_TIMEOUT  500L; //在httpclient4.2.3中我记得它被改成了一个对象导致直接用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);//另外设置http client的重试次数默认是3次当前是禁用掉如果项目量不到这个默认即可 httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));4.2 如果配置了nginx的话nginx也要设置面向两端的keep-alive 现在的业务里没有nginx的情况反而比较稀少。nginx默认和client端打开长连接而和server端使用短链接。 ❝ 注意client端的keepalive_timeout和keepalive_requests参数以及upstream端的keepalive参数设置这三个参数的意义在此也不再赘述。 ❞ 以上就是我的全部设置。通过这些设置成功地将原本每次请求250ms的耗时降低到了80左右效果显著。 JAR包如下 !-- httpclient -- dependencygroupIdorg.apache.httpcomponents/groupIdartifactIdhttpclient/artifactIdversion4.5.6/version /dependency代码如下 //Basic认证 private static final CredentialsProvider credsProvider  new BasicCredentialsProvider(); //httpClient private static final CloseableHttpClient httpclient; //httpGet方法 private static final HttpGet httpget; // private static final RequestConfig reqestConfig; //响应处理器 private static final ResponseHandlerString responseHandler; //jackson解析工具 private static final ObjectMapper mapper  new ObjectMapper();static {System.setProperty(http.maxConnections,50);System.setProperty(http.keepAlive, true);//设置basic校验credsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM),new UsernamePasswordCredentials(, ));//创建http客户端httpclient  HttpClients.custom().useSystemProperties().setRetryHandler(new DefaultHttpRequestRetryHandler(3,true)).setDefaultCredentialsProvider(credsProvider).build();//初始化httpGethttpget  new HttpGet();//初始化HTTP请求配置reqestConfig  RequestConfig.custom().setContentCompressionEnabled(true).setSocketTimeout(100).setAuthenticationEnabled(true).setConnectionRequestTimeout(100).setConnectTimeout(100).build();httpget.setConfig(reqestConfig);//初始化response解析器responseHandler  new BasicResponseHandler(); } /** 功能返回响应* author zhangdaquan* 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; }/** 功能发送http请求并用net.sf.json工具解析* author zhangdaquan* 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; }/** 功能发送http请求并用jackson工具解析* author zhangdaquan* 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; } /** 功能发送http请求并用fastjson工具解析* author zhangdaquan* 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; }
http://www.dnsts.com.cn/news/264253.html

相关文章:

  • 网站开发企业排名网站建设实训报告作业
  • 企业建设网站的目的( )ui特效网站
  • 校园网站建设的感受论文网站建设_聊城
  • 织梦可以放两个网站wordpress腾讯课堂
  • 南昌公司做网站禁止 wordpress ajax
  • 广州专业的做网站企业手机网站建设效果
  • 化妆品 网站模板中国建设信息化期刊官网
  • 站长网站模板网站的icp备案信息
  • wex5网站开发东莞排名优化
  • 鼠标垫东莞网站建设wordpress不显示文章
  • 做包装的网站有哪些深圳城建局
  • 电子商务网站服务器售后网站开发需求文档
  • 我要建立网站创建网站代码是什么
  • 网站设计企业有赞微商城开店收费吗
  • 特色美食网站建设策划书长沙网站设
  • 公司网站建设广州房地产市场需求分析
  • 有没有网站免费的重庆网站建设 微客巴巴
  • 重庆做网站优化推广的公司聊城网站建设聊城
  • 儿童教育网站怎么做有趣如今做知乎类网站怎么样
  • 手机网站模板演示有机大米网站建设方案
  • 鹤山市住房和城乡建设局网站上海官网建设费用
  • 信息网站建设游戏怎么制作的
  • 零售网站制作百度数据库
  • 自己做的网站用在博客上安卓手机优化大师官方下载
  • 网站建设的步骤过程ppt用表格做网站
  • 神网站建设天眼网查个人
  • 网站开发语言是什么西安网页设计招聘信息
  • 网站开发主要流程内蒙古建设厅网站删除
  • 服装官网网站建设网站开发需要做什么工作
  • 企业网站建设 会计分录lnmp架构部署wordpress