`
jsczxy2
  • 浏览: 1255313 次
  • 性别: Icon_minigender_1
  • 来自: 常州
文章分类
社区版块
存档分类
最新评论

HttpClient优化相关

阅读更多

首先,HttpClient可以共用,减少创建HttpClient的开销。当然,如果你的应用调用HttpClient并不怎么频繁的话那就没必要共用了,毕竟在内存中维护一个空闲的httpClient对象是不保险的。

 


其次,Connection可以重用,减少建立连接的开销。

 


要完成以上两点,可以用多线程下的MultiThreadedHttpConnectionManager管理HttpConnection和HttpClient。MultiThreadedHttpConnectionManager管理的HttpClient是线程安全的,可以做成单例的。但是值得注意的是每个线程应该有自己的HttpMethod和HttpState、HttpConfiguration,以区分每次请求的host和HttpSession 。如下所示:

 

private static MultiThreadedHttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();

private HttpClient client = new HttpClient(httpConnectionManager);

 


定义好后,在静态块中初始化相关参数

 

static {              

    //每主机最大连接数和总共最大连接数,通过hosfConfiguration设置host来区分每个主机  

    client.getHttpConnectionManager().getParams().setDefaultMaxConnectionsPerHost(8);

    client.getHttpConnectionManager().getParams().setMaxTotalConnections(48);

    client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

    client.getHttpConnectionManager().getParams().setSoTimeout(5000);

    client.getHttpConnectionManager().getParams().setTcpNoDelay(true);

    client.getHttpConnectionManager().getParams().setLinger(1000);                   

    //失败的情况下会进行3次尝试,成功之后不会再尝试

    client.getHttpConnectionManager().getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());

}

 


HttpConfiguration中有一些参数对提高性能有一些帮助,主要说明如下:

 


DefaultMaxConnectionsPerHost参数定义每台主机允许的最大连接数,默认为2。这个参数只能用于一些特定的httpConnectionManager,比如MultiThreadedHttpConnectionManager。

 


MaxTotalConnections参数表示httpConnectionManager管理的最大连接数,默认为20。同上个参数,这个参数也只是在某些特定的httpConnectionManager中有用。

 


setTcpNoDelay(true)设置是否启用Nagle算法,设置true后禁用Nagle算法,默认为false(即默认启用Nagle算法)。Nagle算法试图通过减少分片的数量来节省带宽。当应用程序希望降低网络延迟并提高性能时,它们可以关闭Nagle算法,这样数据将会更早地发送,但是增加了网络消耗。

 


setLinger(1000)设置socket延迟关闭时间,值为0表示这个选项是关闭的,值为-1表示使用JRE的默认设置。

 


setStaleCheckingEnabled(true)参数设置是否启用旧连接检查,默认是开启的。关闭这个旧连接检查可以提高一点点性能,但是增加了I/O错误的风险(当服务端关闭连接时)。开启这个选项则在每次使用老的连接之前都会检查连接是否可用,这个耗时大概在15-30ms之间[3]。

 


然后,在每个线程代码中,创建自己的HttpMethod。

 


还有一个很重要的优化点是采用请求/响应实体流,尤其是在请求频繁数据量大的情况下,很大的实体不会被缓存在内存中而直接发送或接收,采用流能有效的提高性能。虽然这些实体可以是字符串或者字节数组,但是它们容易导致内存泄露,你得小心的使用他们,因为它们是整个实体缓存在内存中的。

 


对于响应流,采用method的getResponseBodyAsStream()来代替getResponseBody() 和getResponseBodyAsString().如下所示:

 

HttpClient httpclient = new HttpClient();

  GetMethod httpget = new GetMethod("http://www.myhost.com/");

  try {

    httpclient.executeMethod(httpget);

    Reader reader = new InputStreamReader(httpget.getResponseBodyAsStream(), httpget.getResponseCharSet());

    // consume the response entity

  } finally {

    httpget.releaseConnection();

  }

 


而对于请求流,可以通过实现RequestEntity自定义自己的各种流,httpclient包含了常见的几种实现,如FileRequestEntity、ByteArrayRequestEntity、StringRequestEntity、MultipartRequestEntity等。使用示例如下:

 

File myfile = new File("myfile.txt");

PostMethod httppost = new PostMethod("/stuff");

httppost.setRequestEntity(new FileRequestEntity(myfile));

 


如果客户端和服务器的通讯不需要保持会话状态的话,可以通过禁用Cookie来提高一点点性能,比如蜘蛛爬虫之类应用。如下:

 

HttpMethod method = new GetMethod();

method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);

method.setRequestHeader("Cookie", "special-cookie=value");

 


参考资料:

 


1. http://hc.apache.org/httpclient-3.x/performance.html

 

尽管Android官网推荐在2.3及后续版本中使用HttpURLConnection作为网络开发首选类,但在连接管理线程安全方面,HttpClient还是具有很大优势。就目前而言,HttpClient仍是一个值得考虑的选择。对于HttpClient的优化,可以从以下几个方面着手:

    (1)采用单例模式(重用HttpClient实例)
    对于一个通信单元甚至是整个应用程序,Apache强烈推荐只使用一个HttpClient的实例。例如:

    private static HttpClient httpClient = null;
 
    private static synchronized HttpClient getHttpClient() {
       if(httpClient == null) {
           final HttpParams httpParams = new BasicHttpParams();  
           httpClient = new DefaultHttpClient(httpParams); 
       }  
  
      return httpClient;
    }

    (2)保持连接(重用连接)
    对于已经和服务端建立了连接的应用来说,再次调用HttpClient进行网络数据传输时,就不必重新建立新连接了,而可以重用已经建立的连接。这样无疑可以减少开销,提升速度。
    在这个方面,Apache已经做了“连接管理”,默认情况下,就会尽可能的重用已有连接,因此,不需要客户端程序员做任何配置。只是需要注意,Apache的连接管理并不会主动释放建立的连接,需要程序员在不用的时候手动关闭连接。

    (3)多线程安全管理的配置
    如果应用程序采用了多线程进行网络访问,则应该使用Apache封装好的线程安全管理类ThreadSafeClientConnManager来进行管理,这样能够更有效且更安全的管理多线程和连接池中的连接。
    (在网上也看到有人用MultiThreadedHttpConnectionManager进行线程安全管理的,后查了下Apache的API,发现MultiThreadedHttpConnectionManager是API 2.0中的类,而ThreadSafeClientConnManager是API 4.0中的类,比前者更新,所以选择使用ThreadSafeClientConnManager。另外,还看到有PoolingClientConnectionManager这个类,是API 4.2中的类,比ThreadSafeClientConnManager更新,但Android SDK中找不到该类。所以目前还是选择了ThreadSafeClientConnManager进行管理)
    例如:

    ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry); 
    httpClient = new DefaultHttpClient(manager, httpParams);

    (4)大量传输数据时,使用“请求流/响应流”的方式
    当需要传输大量数据时,不应使用字符串(strings)或者字节数组(byte arrays),因为它们会将数据缓存至内存。当数据过多,尤其在多线程情况下,很容易造成内存溢出(out of memory,OOM)。
    而HttpClient能够有效处理“实体流(stream)”。这些“流”不会缓存至内存、而会直接进行数据传输。采用“请求流/响应流”的方式进行传输,可以减少内存占用,降低内存溢出的风险。
    例如:

    // Get method: getResponseBodyAsStream()
    // not use getResponseBody(), or getResponseBodyAsString()
    GetMethod httpGet = new GetMethod(url);  
    InputStream inputStream = httpGet.getResponseBodyAsStream();

    // Post method: getResponseBodyAsStream()
    PostMethod httpPost = new PostMethod(url);  
    InputStream inputStream = httpPost.getResponseBodyAsStream(); 

    (5)持续握手(Expect-continue handshake)
    在认证系统或其他可能遭到服务器拒绝应答的情况下(如:登陆失败),如果发送整个请求体,则会大大降低效率。此时,可以先发送部分请求(如:只发送请求头)进行试探,如果服务器愿意接收,则继续发送请求体。此项优化主要进行以下配置:

    // use expect-continue handshake
    HttpProtocolParams.setUseExpectContinue(httpParams, true);

    (6)“旧连接”检查(Stale connection check)
    HttpClient为了提升性能,默认采用了“重用连接”机制,即在有传输数据需求时,会首先检查连接池中是否有可供重用的连接,如果有,则会重用连接。同时,为了确保该“被重用”的连接确实有效,会在重用之前对其进行有效性检查。这个检查大概会花费15-30毫秒。关闭该检查举措,会稍微提升传输速度,但也可能出现“旧连接”过久而被服务器端关闭、从而出现I/O异常。
    关闭旧连接检查的配置为:
    // disable stale check
    HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);

    (7)超时设置
    进行超时设置,让连接在超过时间后自动失效,释放占用资源。
    // timeout: get connections from connection pool
    ConnManagerParams.setTimeout(httpParams, 1000);  
    // timeout: connect to the server
    HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
    // timeout: transfer data from server
    HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);

    (8)连接数限制
    配置每台主机最多连接数和连接池中的最多连接总数,对连接数量进行限制。其中,DEFAULT_HOST_CONNECTIONS和DEFAULT_MAX_CONNECTIONS是由客户端程序员根据需要而设置的。
    // set max connections per host
    ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS)); 
    // set max total connections
    ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);

    经过优化后,上一篇日志中的getHttpClient()方法代码如下:

   

[java] view plaincopy
 
 
  1. private static synchronized HttpClient getHttpClient() {  
  2.     if(httpClient == null) {  
  3.         final HttpParams httpParams = new BasicHttpParams();    
  4.           
  5.         // timeout: get connections from connection pool  
  6.         ConnManagerParams.setTimeout(httpParams, 1000);    
  7.         // timeout: connect to the server  
  8.         HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);  
  9.         // timeout: transfer data from server  
  10.         HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);   
  11.           
  12.         // set max connections per host  
  13.         ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS));    
  14.         // set max total connections  
  15.         ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);  
  16.           
  17.         // use expect-continue handshake  
  18.         HttpProtocolParams.setUseExpectContinue(httpParams, true);  
  19.         // disable stale check  
  20.         HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);  
  21.           
  22.         HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);    
  23.         HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);   
  24.             
  25.         HttpClientParams.setRedirecting(httpParams, false);  
  26.           
  27.         // set user agent  
  28.         String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";  
  29.         HttpProtocolParams.setUserAgent(httpParams, userAgent);       
  30.           
  31.         // disable Nagle algorithm  
  32.         HttpConnectionParams.setTcpNoDelay(httpParams, true);   
  33.           
  34.         HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);    
  35.           
  36.         // scheme: http and https  
  37.         SchemeRegistry schemeRegistry = new SchemeRegistry();    
  38.         schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));    
  39.         schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));  
  40.   
  41.         ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);    
  42.         httpClient = new DefaultHttpClient(manager, httpParams);   
  43.     }         
  44.       
  45.     return httpClient;  
  46. }  

 

    附录:关于HttpURLConnection的优化,网上资料不多。从Android官网上看到一点,整理如下:

    (1)上传数据至服务器时(即:向服务器发送请求),如果知道上传数据的大小,应该显式使用setFixedLengthStreamingMode(int)来设置上传数据的精确值;如果不知道上传数据的大小,则应使用setChunkedStreamingMode(int)——通常使用默认值“0”作为实际参数传入。如果两个函数都未设置,则系统会强制将“请求体”中的所有内容都缓存至内存中(在通过网络进行传输之前),这样会浪费“堆”内存(甚至可能耗尽),并加重隐患。

    (2)如果通过流(stream)输入或输出少量数据,则需要使用带缓冲区的流(如BufferedInputStream);大量读取或输出数据时,可忽略缓冲流(不使用缓冲流会增加磁盘I/O,默认的流操作是直接进行磁盘I/O的);

    (3)当需要传输(输入或输出)大量数据时,使用“流”来限制内存中的数据量——即:将数据直接放在“流”中,而不是存储在字节数组或字符串中(这些都存储在内存中)。

 

    参考文章:

    http://hc.apache.org/httpclient-3.x/performance.html

    http://blog.csdn.net/androidzhaoxiaogang/article/details/8198400

    http://guowww.diandian.com/post/2011-11-07/15351973

    http://blog.csdn.net/ken831001/article/details/7925309

    http://www.iteye.com/topic/1117362

    http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.html

    http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingClientConnectionManager.html

分享到:
评论

相关推荐

    Android Asynchronous HTTPClient的实现和优化

    Android Asynchronous HTTPClient的实现和优化

    高效池化-JAVA-HttpClient工具类

    1.高效简单池化的HttpClient工具类,提供单元测试用列。 2.支持基于SpringBoot 2.1.x的自动装载模块,引用依赖即可使用。 3.公司几十个项目都使用该工具类访问第三方的Http/Https+json协议接口。 4.经过上市公司多个...

    AndroidHttpClient详解及调用示例

    前言: 这类其实是Google对阿帕奇的HttpClient的一个封装,一些默认属性有android做了一些优化。 然后阿帕奇的HttpClient是对java中HttpUrlConnection的一个封装,感觉阿帕奇封装的还是不错的, 特别是其中的...

    使用java的HttpClient实现多线程并发

    主要介绍了使用java的HttpClient实现多线程并发的相关资料,需要的朋友可以参考下

    HttpClient介绍和使用

    1. HttpClient简介 ...HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富...2.1 引入jar包,新版有优化,我这新的是v4.5.10,旧的是v4.1.2 org.apache.httpcomponents httpclient

    Android也架构之三:简单工厂模式优化网络请求

    拥抱变化,让我们冲现在开始吧,上一篇文章《Android也架构之二:单例模式访问网络》中,我们学会用了单例模式,单例模式一般解决的是和程序相关的问题,和业务逻辑无关,今天开始,我们就开始学习和业务相关的设计...

    OkOne:基于okhttp库的网络性能优化框架

    好吧基于okhttp库的网络性能优化框架简介在APP项目中可能会包含多个组件模块,或依赖多个三方库,其中可能有使用到okhttp框架进行网络请求。不同的组件模块和三方库间相互创建OkHttpClient实例,或有开发者未通过...

    15.tornado的httpclient模块使用介绍.zip

    网络爬虫基础 网络爬虫的概述和原理 ...Python爬虫库的介绍 数据抓取与解析 ...数据存储格式的选择和优化 实际案例分析 应用所学知识解决真实世界中的爬虫和IO问题 爬虫和IO项目开发流程与实践经验分享

    go语言HttpClient,基于goz改造 相对原版改动较大,造成了不兼容原版结局.rar

    但分布式系统也给开发以及运维人员带来了难题:如何监控和优化分布式系统的行为。 以google为例,想象一下,用户通过浏览器发起一个搜索请求,Google后端可能会有成百上千台机器、多种编程语言实现的几十个、上百个...

    Spring Cloud Feign性能优化代码实例

    主要介绍了Spring Cloud Feign性能优化代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    Feign HTTP Client 使用指南 - Tower.pdf

    默认情况下,feign通过jdk中的HttpURLConnection向下游服务发起http请求,这种情况下,由于缺乏连接池的支持,在达到一定流量的后服务肯定会出问题.本指南详细介绍feign的实现以及优化

    Windchill系统及数据库优化配置.txt

    -- For System Start up --> $(wt.java.cmd.quoted) $(wt.manager.cmd.common.java.args) -Djava.protocol.handler.pkgs=HTTPClient -DHTTPClient.disableKeepAlives=true -DHTTPClient.dontChunkRequests=true -Xms...

    java研究室,包含了各种小程序:文件上传,httpclient操作,数据库访问,图片操作等,方便在工作中快速取用.zip

    此外,其背后的开发团队持续迭代更新,根据用户反馈不断优化产品性能,提升服务质量,致力于打造一个贴近用户需求、充满活力的小程序生态。 总结来说,【小程序名称】凭借其小巧便携、快捷高效的特性,不仅节省了...

    WebMagic 0.4.0 发布,Java爬虫框架

    此次更新主要对下载模块进行了优化 并增加了同步下载的API 同时对代码进行了一些重构 一 Downloader部分更新: 升级HttpClient到4 3 1 重写了HttpClientDownloader的代码 #32 在http请求中主动开启gzip 降低传输...

    JavaSerialPort:Java 串口通信、swing界面优化

    httpclient-get\post请求 环境、工具 windows 10 64位 JDK1.7 Eclipse Java EE IDE for Web Developers(Version: Kepler Service Release 2) WindowBuilder 工具包 AbsoluteLayout.jar swing-layout-1.0.3.jar /...

    okhttps轻量级HTTP客户端.rar

    目前项目已经更新至2.2.2版本,并且会持续进行迭代优化。 前言 Retrofit是适用于Android和Java且类型安全的HTTP客户端,其最大的特性的是支持通过接口的方式发起HTTP请求。而spring-boot是使用最广泛的Java开发框架...

    JAVA 调用百度API实现了人脸检测和人脸对比 并在GUI显示

    就两个字,免费,哈哈,发到CSDN,给大家看,然后我自己顺便存一下资料什么的,请大家指出错误,里面还是有很多毛病,比如说,我写之前没有设计...还有项目我还没有好好优化,管理什么的,里面有一些代码比较乱还有多余

    Android App开发中HTTP扩展包OkHttp的入门使用指南

    Google 推荐使用 HttpURLConnection,究其原因,就是由于 HttpClient 的 API 数量过多,使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前 Android 团队在提升和优化 HttpClient 方面的工作态度并不...

    Eclipse开发分布式商城系统+完整视频代码及文档

    │ workspace.zip │ 列表生成.reg │ 淘淘商城源代码.zip │ ├─01....│ ├─相关资料 │ │ redis-3.0.1.tar.gz │ │ redis-3.0.2.tar.gz │ │ redis-3.2.1.gem │ │ Redis集群.docx │ │ ...

    SeimiCrawler(Java 爬虫框架) v1.3.0.zip

    默认下载器改为Apache Httpclient,备用为下载器OkHttp3实现 优化部分代码 demo日志默认全部输出至控制台 SeimiCrawler(Java 爬虫框架)简介 SeimiCrawler是一个敏捷的,独立部署的,支持分布式的Java爬虫框架,...

Global site tag (gtag.js) - Google Analytics