HttpURLConnection的性能问题

时间:2014-04-28 14:04:43

标签: java performance httpurlconnection

我基本上使用以下两种方法为WebServer建立HttpURLConnection

    private HttpURLConnection establishConnection(URL url) {
    HttpURLConnection conn = null;
    try {
        conn = (HttpURLConnection) url.openConnection();
        conn = authenticate(conn);
        conn.setRequestMethod(httpMethod);
        conn.setConnectTimeout(50000);
        conn.connect();
        input= conn.getInputStream();
        return conn;
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    return null;
}

private HttpURLConnection authenticate(HttpURLConnection conn) {
    String userpass = webServiceUserName + ":" + webServicePassword;
    byte[] authEncBytes = Base64.encodeBase64(userpass.getBytes());
    String authStringEnc = new String(authEncBytes);
    conn.setRequestProperty("Authorization", "Basic " + authStringEnc);
    return conn;
}

这很有效,服务器正在发送一些XML文件,我可以继续使用它。我遇到的问题是,我必须做大约220个这样的问题,它们加起来大约需要25秒的处理时间。数据用于WebPage,因此25秒的响应时间并不可接受。 上面的代码需要大约:86000036ns(~86ms),所以我正在寻找一种方法以某种方式提高速度。我尝试使用org.apache.http.*包,但这比我当前的实现慢一点。

由于

马库斯

修改:input=conn.getInputStream(); 负责延迟~82-85ms。无论如何"周围"它?

Edit2:我也使用过Connection Manager PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(200); cm.setDefaultMaxPerRoute(20); HttpHost localhost = new HttpHost(webServiceHostName, 443); cm.setMaxPerRoute(new HttpRoute(localhost), 50); CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope(webServiceHostName, 443), new UsernamePasswordCredentials(webServiceUserName, webServicePassword)); httpclient = HttpClients.custom().setConnectionManager(cm).setDefaultCredentialsProvider(credsProvider).build();

但运行时间增加到〜40秒,并且在每次请求Cookie被拒绝后,我都会收到来自Tomcat的警告,因为有非法路径属性"

2 个答案:

答案 0 :(得分:1)

通过并行下载大量文件,您可以获得实质性的提升。

我有一个项目,我必须通过卫星回程从服务器下载20个资源(大约700毫秒往返延迟)。按顺序下载它们大约需要30秒; 5次一次需要6.5秒,10次一次需要3.5秒,而所有20次一次只需2.5秒。

这是一个将同时执行多个下载的示例,如果服务器支持,将使用连接保持活动。

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

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.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

public class Downloader {
    private static final int MAX_REQUESTS_PER_ROUTE = 10;
    private static final int MAX_REQUESTS_TOTAL = 50;
    private static final int MAX_THREAD_DONE_WAIT = 60000;

    public static void main(String[] args) throws IOException,
            InterruptedException {

        long startTime = System.currentTimeMillis();

        // create connection manager and http client
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setDefaultMaxPerRoute(MAX_REQUESTS_PER_ROUTE);
        cm.setMaxTotal(MAX_REQUESTS_TOTAL);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setConnectionManager(cm).build();

        // list of download items
        List<DownloadItem> items = new ArrayList<DownloadItem>();
        items.add(new DownloadItem("http://www.example.com/file1.xml"));
        items.add(new DownloadItem("http://www.example.com/file2.xml"));
        items.add(new DownloadItem("http://www.example.com/file3.xml"));
        items.add(new DownloadItem("http://www.example.com/file4.xml"));

        // create and start download threads
        DownloadThread[] threads = new DownloadThread[items.size()];
        for (int i = 0; i < items.size(); i++) {
            threads[i] = new DownloadThread(httpclient, items.get(i));
            threads[i].start();
        }

        // wait for all threads to complete
        for (int i = 0; i < items.size(); i++) {
            threads[i].join(MAX_THREAD_DONE_WAIT);
        }

        // use content
        for (DownloadItem item : items) {
            System.out.println("uri: " + item.uri + ", status-code: "
                    + item.statusCode + ", content-length: "
                    + item.content.length);
        }

        // done with http client
        httpclient.close();

        System.out.println("Time to download: "
                + (System.currentTimeMillis() - startTime) + "ms");
    }

    static class DownloadItem {
        String uri;
        byte[] content;
        int statusCode;

        DownloadItem(String uri) {
            this.uri = uri;
            content = null;
            statusCode = -1;
        }
    }

    static class DownloadThread extends Thread {
        private final CloseableHttpClient httpClient;
        private final DownloadItem item;

        public DownloadThread(CloseableHttpClient httpClient, DownloadItem item) {
            this.httpClient = httpClient;
            this.item = item;
        }

        @Override
        public void run() {
            try {
                HttpGet httpget = new HttpGet(item.uri);
                HttpContext context = new BasicHttpContext();
                CloseableHttpResponse response = httpClient.execute(httpget,
                        context);
                try {
                    item.statusCode = response.getStatusLine().getStatusCode();
                    HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        item.content = EntityUtils.toByteArray(entity);
                    }
                } finally {
                    response.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

答案 1 :(得分:0)

如果不知道您的网络请求的工作类型,我认为超过 99% 25秒包含网络时间,并等待各种资源响应(磁盘系统,LDAP服务器,名称服务器等)。

光速

我看到你对网络服务器使用用户名/密码。这是一个外部网络服务器吗?如果是这样,网络距离本身可以占86毫秒。随着许多要求,你开始感受到光速的限制。

优化程序的方法是最大限度地减少堆叠的所有等待时间。这可以通过并行运行请求,或者在一个请求中允许多个请求(如果您可以在Web服务器上进行更改)来完成。

如果仍按顺序运行请求,连接池本身不会解决问题。

可能的解决方案

根据评论中的进一步说明,您可以使用以下顺序:

  1. 请求概述XML。
  2. 从概述XML中提取设备列表。
  3. 并行请求所有设备的设备详细信息。
  4. 收集所有请求的回复。
  5. 再次运行XML,这次使用响应进行更新。