Using HttpClient repeatedly giving me OOM exception(?)

192 views
Skip to first unread message

Kevin Clarke

unread,
Sep 19, 2016, 11:01:53 AM9/19/16
to vert.x
Hi,

I'm not sure if I'm doing something wrong or just missing an important step when using HttpClient. I have a case where I want to submit a lot of PUTs using a single HttpClient. I've distilled my usage down to some sample code at: https://github.com/ksclarke/vertx-httpclient-test/blob/master/src/main/java/test/Test.java

I thought calling request.end(Buffer) would be all that's needed to conclude the use of an individual request but when I run this sample code eventually I run out of memory (I can set my test application's  Xmx memory to 2G or something to make it happen quickly). If I look at the crash report I see: 'One instance of "io.vertx.core.http.impl.ConnectionManager$ConnQueue' loaded by 'sun.misc.Launcher$AppClassLoader @ 0x6000592d0' occupies 5,624,581,384 (99.66%) bytes. The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader>." It seems there are a bunch of io.vertx.core.http.impl.HttpClientRequestImpl$2 instances hanging around in an ArrayDeque.

Would someone mind looking at my example code and let me know if I'm missing some step to cleanup the PUT request after it's completed?

Thanks,
Kevin

Kevin Clarke

unread,
Sep 19, 2016, 11:06:50 AM9/19/16
to vert.x
Or is it just that it's creating too many requests before they can be processed? I'm new to this style of programming.

Thanks,
Kevin

Julien Viet

unread,
Sep 19, 2016, 11:51:59 AM9/19/16
to ve...@googlegroups.com
yes your requests are queued for execution and your test is not realistic.

to prevent that you can set the maxQueueWaitSize on HttpClientOptions to a value that will prevent to enqueue too many requests, the default value is unbounded.

-- 
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
Visit this group at https://groups.google.com/group/vertx.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/c0b026c4-eb7d-46ff-9c33-d43a3ad007d7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kevin Clarke

unread,
Sep 19, 2016, 12:11:59 PM9/19/16
to vert.x
On Monday, September 19, 2016 at 11:51:59 AM UTC-4, Julien Viet wrote:
your test is not realistic.

Well, it is what I need to do in my real use case.  :-)
 
to prevent that you can set the maxQueueWaitSize on HttpClientOptions to a value that will prevent to enqueue too many requests, the default value is unbounded.

Ah, thanks! So I can catch that exception when it's too congested and keep checking back for when it's not to finish submitting the rest of the requests.

Thank you,
Kevin

Julien Viet

unread,
Sep 19, 2016, 1:07:24 PM9/19/16
to ve...@googlegroups.com
On Sep 19, 2016, at 6:11 PM, Kevin Clarke <kscl...@gmail.com> wrote:

On Monday, September 19, 2016 at 11:51:59 AM UTC-4, Julien Viet wrote:
your test is not realistic.

Well, it is what I need to do in my real use case.  :-)

I think there are two things to distinguish:

1/ the request pace - 

In this case I mean that if you were doing these requests in reaction to network requests (like it is often the case), that would be less likely to happen.

if you are doing requests based let’s say on a configuration file, then you need indeed to pace the requests.

I think it lies also in the design of the HttpClient that provides a lazy API, i.e not callback based. So to schedule a request, you need to write buffers to it and end it.

With an API like:

client.get(“http://myhost/mypath”, Handler< HttpClientRequest> handler);

then the handler would be called when the request is ready to be sent, so you would load your buffers at this moment.

current we have :

HttpClientRequest req = client.get(…);

where you think that the request is ready to be sent where as it is not the case.

2/ you are also preallocated buffers on heap (which are actually the source of OOM) and write them directly to the request.

using a ReadStream<Buffer> (like an AsynFile, or whatever implementation) with a Pump instead would allow to apply back-pressure on the read stream and load the buffers when they are needed.

 
to prevent that you can set the maxQueueWaitSize on HttpClientOptions to a value that will prevent to enqueue too many requests, the default value is unbounded.

Ah, thanks! So I can catch that exception when it's too congested and keep checking back for when it's not to finish submitting the rest of the requests.

yes you can do that.

if you need to do more requests at the same time you can also increase the size of the connection pool per host and use keep-alive


Thank you,
Kevin


 

On Sep 19, 2016, at 5:06 PM, Kevin Clarke <kscl...@gmail.com> wrote:

Or is it just that it's creating too many requests before they can be processed? I'm new to this style of programming.

Thanks,
Kevin



On Monday, September 19, 2016 at 11:01:53 AM UTC-4, Kevin Clarke wrote:
Hi,

I'm not sure if I'm doing something wrong or just missing an important step when using HttpClient. I have a case where I want to submit a lot of PUTs using a single HttpClient. I've distilled my usage down to some sample code at: https://github.com/ksclarke/vertx-httpclient-test/blob/master/src/main/java/test/Test.java

I thought calling request.end(Buffer) would be all that's needed to conclude the use of an individual request but when I run this sample code eventually I run out of memory (I can set my test application's  Xmx memory to 2G or something to make it happen quickly). If I look at the crash report I see: 'One instance of "io.vertx.core.http.impl.ConnectionManager$ConnQueue' loaded by 'sun.misc.Launcher$AppClassLoader @ 0x6000592d0' occupies 5,624,581,384 (99.66%) bytes. The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader>." It seems there are a bunch of io.vertx.core.http.impl.HttpClientRequestImpl$2 instances hanging around in an ArrayDeque.

Would someone mind looking at my example code and let me know if I'm missing some step to cleanup the PUT request after it's completed?

Thanks,
Kevin

-- 
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
Visit this group at https://groups.google.com/group/vertx.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/c0b026c4-eb7d-46ff-9c33-d43a3ad007d7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
Visit this group at https://groups.google.com/group/vertx.

Kevin Clarke

unread,
Sep 19, 2016, 1:30:16 PM9/19/16
to vert.x
Thanks for the additional information. Right, my case has me loading from an input file so there is no network on the input to help pace the processing.

I see what you're saying about client.get(“http://myhost/mypath”, Handler< HttpClientRequest> handler);

That doesn't currently exist though, right? There is just the client.put("http://myhost/mypath", Handler <HttpClientResponse> handler);?

Re: #2 ... I haven't looked into the Pump stuff yet really, but it sounds like you're saying that would also be a solution for me. It allows me to set it all up but not actually load the content until it's ready to be put?

I'll also look into the connection pool per host and keep-alive.

Thanks,
Kevin

Kevin Clarke

unread,
Sep 19, 2016, 1:57:43 PM9/19/16
to vert.x
Fwiw, the client.get(“http://myhost/mypath”, Handler< HttpClientRequest> handler); scenario you describe might be useful for another one of my cases. I'm using a vertx library that abstracts working with AWS' S3. Currently, the library creates the signature that S3 needs on end(). I also generate a large number of backlog requests and by the time the actual put is called on some of the later ones the signature (which includes a date) is no longer valid. In your HttpClientRequest scenario the signature could wait to be created until it was actually ready to do the put. Alternatively, I could pace the creation of those requests so that the queue isn't so large.

Thanks,
Kevin

Julien Viet

unread,
Sep 20, 2016, 2:49:16 AM9/20/16
to ve...@googlegroups.com
the pump is definitely what makes Vert.x handle back-pressure when streaming.

the goal of back-pressure is to limit the amount of memory and queuing.

Reply all
Reply to author
Forward
0 new messages