Jersey客户端非阻塞

10
大量创建线程从来都不是一个好主意(如果您创建太多线程,可能会耗尽内存)。通常情况下,Jersey每个请求需要创建一条线程。无论是使用async()(在这种情况下,Jersey为我创建线程,我已经在调试器中进行了研究),还是不使用(在这种情况下,我显然必须自己创建线程),这似乎都是适用的。所以这里有一个具体的情况表明这样做还不够好:我正在以每秒多达500个请求的速度向远程服务器发送HTTP POST请求。但是由于响应可能要花费一些时间才能到达(我计算最多需要30秒),因此总线程数很容易达到几千个(此时,JVM进程通常会崩溃)。此外,创建如此多的线程就是疯狂的。对于可用的处理器/网络/操作系统资源来处理这个负载实际上应该很容易。
所以我想做的就是仅仅发出请求,并且在HTTP响应到达时由操作系统通知我。简单地使用target.request(...).async()并不起作用(因为在这种情况下,Jersey只会生成它自己的线程)。此外,限制线程数量通过new ClientConfig().property(ClientProperties.ASYNC_THREADPOOL_SIZE, 10)根本没有帮助,因为这意味着最多只能同时发送10个请求,这显然不是我想要的(它只会堆积队列)。我尝试使用new ClientConfig().connectorProvider(new GrizzlyConnectorProvider())来获取NIO支持,但根本没有看到任何行为上的差异。那么有没有一种方法可以发出请求而不必为每个请求创建一个额外的线程呢?

我刚发现,有一个叫做 jersey-non-blocking-client 的项目,还有一篇相对应的博客文章,作者在其中解决了这个问题(虽然他严重低估了非阻塞和阻塞之间的影响)。 然而,不幸的是,该项目适用于Jersey的旧版本,而我无法使用。也许Jersey的新版本已经支持非阻塞方式了?如果是的话,如何激活它呢? - Chris Lercher
你可以启动的线程数量首先取决于堆空间。2048并没有什么神奇之处。 - user207421
@EJP:谢谢,我已经纠正了问题。 - Chris Lercher
1
@EJP:顺便说一下,我看到的2048限制似乎是由Mac OS X强制执行的:sysctl kern.num_taskthreads显示kern.num_taskthreads: 2048 - 而且似乎Oracle JVM实际上使用内核线程(有趣)。 - Chris Lercher
2个回答

6

我正在使用CloseableHttpAsyncClient向外部服务进行异步请求。在每秒处理数百个请求时,它能够正常工作,但我没有像您这样观察到线程的数量。这是一个外部依赖项,可以通过Maven集成。

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpasyncclient</artifactId>
  <version>4.0.1</version>
</dependency>

希望这有所帮助。

1
最终,我选择了Apache的HttpAsyncClient(我也尝试了@Alper建议的AsyncHttpClient,它也非常好用 - 只是有一些小差异)。就我所知,目前版本的Jersey无法提供非阻塞行为,因为它受到JAX-RS 2.0的限制(一些文章提到,这可能会在JAX-RS 3.0中实现)。 - Chris Lercher

2

是的,AsyncHttpClient做得很好 - 它创建了一个工作线程池,并且可以处理比工作者更多的活动请求。然而,重新设计我们的应用程序以使用AsyncHttpClient需要相当大的努力,因为我们使用了许多Jersey功能...难道不能通过Jersey实现同样的效果吗? - Chris Lercher
我们使用Jersey作为我们的服务端点,当我们需要调用另一个服务时,我们使用AsyncHttpClient。如果您已经在使用Jersey客户端,我猜这可能不是很容易更改。您可以使用ExecutorService和Future,将调用从调用线程中移开并完成相同的操作。我会再添加一个例子。 - Alper Akture
使用自己的线程池并不能真正解决问题:如果线程池是有界的,并且我使用同步调用到Jersey,那么执行器的调用者将会被阻塞。如果我使用异步调用到Jersey,那么不幸的是Jersey会创建它自己的线程(不仅仅是工作线程,而是每个打开请求一个线程)...(唯一可能起作用的事情是使用同步调用,然后杀死我的线程-但这感觉像是一个非常糟糕的主意)。 - Chris Lercher
你说得对,那个例子并不能解决任何问题,我已经把它删除了。 - Alper Akture
1
你也看过这个了吧,作为一种可能性?链接 - Alper Akture
1
@AlperAkture的建议是使用Jersey异步与AsyncHttpClient,非常实用。正是我所需要的。 - bluecollarcoder

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