【问题标题】:Fire and forget for HTTP in JavaJava中的HTTP一劳永逸
【发布时间】:2016-11-11 15:51:50
【问题描述】:

我们正在实施我们自己的分析,为此我们公开了一个需要调用的 Web 服务,该服务将捕获我们数据库中的数据。

问题在于,由于这是分析,我们会进行大量调用(例如每次页面加载、每次 js 加载后调用、CSS 加载等...),因此会有很多这样的调用。所以我不希望服务器加载大量请求以更精确地等待响应。因为我们得到的回应对我们几乎没有任何用处。

那么有什么方法可以触发 Web 服务请求而忘记我已经触发了它?

我知道每个 HTTP 请求也会有响应。

所以我想到的一件事是如果我们将请求超时设置为零秒怎么办?但我不确定这是否是正确的做法。

请给我更多建议

【问题讨论】:

  • 不要在每次要记录的事件发生时进行调用,而是收集事件数据并减少调用次数。
  • 在某些时候你可以考虑使用 UDP。

标签: java httprequest httpclient analytics httpresponse


【解决方案1】:

您可能会发现以下AsyncRequestDemo.java 很有用:

import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.http.client.fluent.Async;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;

/**
 * Following libraries have been used:
 * 
 * 1) httpcore-4.4.5.jar
 * 2) httpclient-4.5.2.jar
 * 3) commons-logging-1.2.jar
 * 4) fluent-hc-4.5.2.jar     * 
 *
 */

public class AsyncRequestDemo {
    public static void main(String[] args) throws Exception {
    URIBuilder urlBuilder = new URIBuilder()
                               .setScheme("http")
                               .setHost("stackoverflow.com")
                               .setPath("/questions/38277471/fire-and-forget-for-http-in-java");

    final int nThreads = 3; // no. of threads in the pool
    final int timeout = 0; // connection time out in milliseconds

    URI uri = null;
    try {
        uri = urlBuilder.build();
    } catch (URISyntaxException use) {
        use.printStackTrace();
    }

    ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
    Async async = Async.newInstance().use(executorService);
    final Request request = Request.Get(uri).connectTimeout(timeout);

        Future<Content> future = async.execute(request, new FutureCallback<Content>() {
            public void failed(final Exception e) {
                System.out.println("Request failed: " + request);
                System.exit(1);
            }

            public void completed(final Content content) {
                System.out.println("Request completed: " + request);
                System.out.println(content.asString());
                System.exit(0);
            }

            public void cancelled() {
            }
        });

        System.out.println("Request submitted");

    }

}

【讨论】:

  • 这个解决方案比我想象的要好,但是仍然会有 12 个(或任何线程池大小)线程。这里的问题是我们 R 使用它进行分析,所以我们需要服务很多请求。我们还能想点别的吗?可能是某个大小 n 的线程池将网络超时设置为零?
  • 嗨@GokulKulkarni 两个方面i)threadpool with some size n 和ii)network time-out 已包含在答案中。请看一下。
【解决方案2】:

我用过这个:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

  URL url = new URL(YOUR_URL_PATH, "UTF-8")); 
               ExecutorService executor = Executors.newFixedThreadPool(1); 
               Future<HttpResponse> response = executor.submit(new HttpRequest(url));
               executor.shutdown();

对于 HttpRequest、HttpResponse

public class HttpRequest implements Callable<HttpResponse> {
        private URL url;

        public HttpRequest(URL url) {
            this.url = url;
        }

        @Override
        public HttpResponse call() throws Exception {
            return new HttpResponse(url.openStream());
        }
}

public class HttpResponse {
     private InputStream body;

        public HttpResponse(InputStream body) {
            this.body = body;
        }

        public InputStream getBody() {
            return body;
        }
}

就是这样。

【讨论】:

【解决方案3】:

是的,您可以在不等待响应的情况下发起请求并断开连接... 但是您可能不想这样做。服务器端必须处理不正常的断开连接的开销将远远超过让它继续返回响应。

在 Java servlet 中解决此类性能问题的更好方法是将请求中的所有数据推送到队列中,立即响应,并让一个或多个工作线程从队列中取出项目进行处理(例如将其写入数据库)。

【讨论】:

  • '开销......将远远超过'为什么?不通过网络发送数据怎么能比通过网络发送数据更糟糕。
  • 因为 Java 会抛出异常,生成堆栈跟踪等...必须处理。如果关注的是性能,那将变得昂贵。连接/握手已经建立,因此完成响应(即使是空的)比断开连接更安全。顺便说一句 - 我没有说你做不到。我说你可能不想。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-20
  • 2017-06-16
  • 2016-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多