Java非阻塞HTTP客户端

11

我有一个高流量的Java应用程序,需要向另一个服务器发送HTTP POST请求。 目前我正在使用org.apache.commons.httpclient库:

private static void sendData(String data) {
HttpClient httpclient = new HttpClient();
StringRequestEntity requestEntity;
try {
    requestEntity = new StringRequestEntity(data, "application/json", "UTF-8");
    String address = "http://<my host>/events/"
    PostMethod postMethod = new PostMethod(address);
    postMethod.setRequestEntity(requestEntity);

    httpclient.executeMethod(postMethod);

} catch (Exception e) {
    LOG.error("Failed to send data ", e);

}
}

这意味着我正在同步发送我的http请求,这不适合我的多线程高并发应用程序。因此,我想将这些调用更改为异步非阻塞的http调用。

我正在尝试多个选项,例如apache async clientxsocket,但无法使其工作。

尝试过ning:

private static void sendEventToGrpahiteAsync(String event) {
LOG.info("\n" + "sendEventToGrpahiteAsync");
try (AsyncHttpClient asyncHttpClient = new AsyncHttpClient()) {
    BoundRequestBuilder post = asyncHttpClient.preparePost();
    post.addHeader("Content-Type", "application/json");
    post.setBodyEncoding("UTF-8");
    post.setBody(event);
    post.execute(new HttpRequestCompletionHandler());
} catch (Exception e) {
    LOG.error("Failed to sending event", e);
}
}

我尝试了Apache HttpAsyncClient

private static void sendEventToGrpahiteAsync(String event) {
LOG.info("\n" + "sendEventToGrpahiteAsync");
try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {
    httpclient.start();
    HttpPost request = new HttpPost(addr);
    StringEntity entity = new StringEntity(event, ContentType.create("application/json", Consts.UTF_8));
    request.setEntity(entity);
    httpclient.execute(request, null);
} catch (Exception e) {
    LOG.error("Failed to sending event", e);
}
}

我尝试使用xsocket

private static void sendEventToGrpahiteAsync2(String event) {
LOG.info("\n" + "sendEventToGrpahiteAsync");
try (INonBlockingConnection con = new NonBlockingConnection(<SERVER_IP>, 80);
    IHttpClientEndpoint httpClientConnection = new HttpClientConnection(con)) {
    IHttpResponseHandler responseHandler = new MyResponseHandler();
    IHttpRequest request = new PostRequest(url_address, "application/json", Consts.UTF_8.toString(), event);
    request.setTransferEncoding(Consts.UTF_8.toString());
    httpClientConnection.send(request, responseHandler);
} catch (Exception e) {
    LOG.error("Failed to sending event", e);
}
}

我没有收到任何异常,但是帖子也没有到达目标。

需要明确的是,目标是一个Graphite服务器,因此一旦帖子到达,它就会在图表中清晰地显示出来。同步帖子正常工作,我可以在图表上看到结果,但是我的目标图表上没有显示任何异步帖子。

我错过了什么吗?

谢谢


只需将“apache异步客户端”的第一个示例从“HttpGet”更改为“HttpPost”。 - Sotirios Delimanolis
发一篇带有可行示例的答案,赚取一些积分如何? - forhas
2个回答

4

我明白了。

我使用的所有库都使用额外的IO线程实现,因此我的进程可能在完全握手之前结束。

在每个http调用后添加Thread.sleep(2000)后,一切都正常工作了。所以对于Web应用程序(这是我的情况),我建议的实现方式非常好(但对于Java进程,您可以考虑NickJ的答案)。


2
如果您使用额外的IO线程,仍然会损害整个线程池,对吧?到最后,您使用了1个线程来处理回调,是吗? - Diego Ramos

-2
你可以使用Java Executor框架: 首先,创建一个Callable来完成你的工作:
public class MyCallable implements Callable<MyResult> {
  @Override
  public MyResult call() throws Exception {
    //do stuff
    return result;
  }
} 

获取一个将运行您的Callable的执行程序。 有多种获取方法,这里是一个示例:
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);

最后,运行它:

MyCallable callable = new MyCallable();
Future<MyResult> futureResult = executor.submit(callable);

获取结果:

boolean resultReady = futureResult.isDone(); //is the result ready yet?
Result r = futureResult.get(); //wait for result and return it

try {
  Result r = futureResult.get(10, TimeUnit.SECONDS); //wait max. 10 seconds for result
} catch (TimeOutException e) {
  //result still not ready after waiting 10 seconds
}

不错,但我更愿意使用一个可以为我完成这项工作的库,除非没有可用的库,但据我所见还是有一些的。 - forhas
9
这是否只是针对每个请求启动一个线程,而非真正的非阻塞 I/O? - necromancer
7
这与在调用线程上阻塞没有区别。您应该使用NIO客户端进行适当的非阻塞请求。 - HaxElit
1
这与OP所问的完全无关。 @forhas HttpClient是多线程的,因此它可以适合您的用例。但是我认为您正在寻找一个更高吞吐量的客户端,因此使用基于NIO的非阻塞客户端是有意义的。您应该在问题中澄清这一点。 还要记住,只有在需要处理更多并发连接时,NIO客户端才会有所帮助,否则常规BIO客户端就足够了。 - Ravi Sanwal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接