我需要在高负载下使用HttpAsyncClient。我这样创建HttpAsyncClient:
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(CONNECT_TIMEOUT)
.setSocketTimeout(SOCKET_TIMEOUT)
.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
.build();
HttpAsyncClient client = HttpAsyncClients.custom()
.setDefaultRequestConfig(createRequestConfig())
.build();
然后我像这样使用它:
HttpPost request = new HttpPost(url);
request.setEntity(new StringEntity(requestBody, "UTF-8"));
client.execute(request, null)
通常,我不太在乎响应,所以我不初始化
Future<HttpResponse>
变量,也不做Future.get()
。好吧,只是为了澄清(我认为这与问题无关),我有时会在乎回复,但是99%的回复对我来说并不有趣。问题是当我执行大量请求时(例如每秒300个,这里用“ request”一词指的是
client.execute()
调用),我终于得到了java.lang.OutOfMemoryError: GC overhead limit exceeded
。我试图使用VisualVM找出正在发生的事情。我发现java.lang.Object[]
,char[]
,java.lang.String
,byte[]
,short
,char[]
实例数量正在增长(我试图强制GC并限制堆大小以确保它不正常-没有帮助)。因此,增加了使用的堆空间。是什么导致此问题?也许我应该以其他方式使用
HttpAsyncClient
?我需要使用自定义RequestProducer
,ResponseProducer
还是使用CountDownLatch
?UPD
问题是由于PowerMock库
最佳答案
HttpAsyncClient不会以任何方式或方式来限制请求的执行速度,以避免阻塞#execute方法。一个人可以向客户端提交无数个请求,客户端将尽职尽责地将所有请求都放入执行队列中。实际执行这些请求并将其从队列中删除的速度是完全不同的情况,并且可能取决于许多因素。在您的特定情况下,您尝试处理每个路由仅具有2个并发连接的所有这些请求,这不一定是最佳选择。
PS:/老人的抱怨/人们不应该因为某些原因而认为异步客户端会更快。除非将其用于特定用例并以特定方式使用,否则它们将不会被使用。可以肯定的是,除非非常小心,否则异步客户端可能会轻易使用更多的内存。