hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Oleg Kalnichevski <ol...@apache.org>
Subject Re: HttpCore NIO and concurrent session count control
Date Tue, 25 Sep 2012 20:05:16 GMT
On Tue, 2012-09-25 at 20:50 +0400, Dmitry Potapov wrote:
> Hello everyone,
> 
> I'm trying to implement HttpAsyncResponseProducer using
> SharedOutputBuffer and found that I'm unable to control amount of
> concurrent response producers. Most probably, this problem comes from
> my incorrect understanding of HttpAsyncResponseProducer design. So,
> let me explain, how I'm solving this problem now and what problems I
> expect if I will use response producer.
> 
> Currently, in HttpAsyncRequestHandler<HttpRequest>.handle(), I create
> worker object, which will write content to PipedOutputStream, and push
> it into executor (mine implementation of Executor.execute() will block
> if there is no idle worker threads to process passed task). After
> Executor.execute() returns I call
> HttpAsyncExchange.submitResponse(BasicAsyncResponseProducer(response))
> where response contains InputStreamEntity, which handles corresponding
> PipedInputStream.
> That's it, amount of concurrent HttpAsyncContentProducer objects is
> limited by executor queue.
> 
> In case of HttpAsyncResponseProducer I'm using the following logic:
> 1. In HttpAsyncRequestHandler<HttpRequest>.handle() I'm submitting my
> implementation of HttpAsyncResponseProducer to
> HttpAsyncExchange.submitResponse().
> 2. In HttpAsyncResponseProducer.produceContent() checks if it is a
> first call, and if so creates SharedOutputBuffer using passed
> IOControl and, using created buffer, creates new worker object and
> pass it to executor.
> 3. If this wasn't a first call to
> HttpAsyncResponseProducer.produceContent() then I simply call
> SharedOutputBuffer.produceContent()
> 
> The problem is that all IOReactor worker threads can stuck in
> Executor.execute() and Executor worker threads will stuck on
> SharedOutputBuffer.write(), because all IOReactor worker threads
> waiting for their completion.
> 
> There is another approach which can help avoid problem described
> above. Executor.execute() can reject task (by throwing an exception)
> if there is no idle workers. In case of exception
> HttpAsyncResponseProducer.produceContent() will do nothing and will
> try to create SharedOutputBuffer and task on the next
> HttpAsyncResponseProducer.produceContent() invocation. But in this
> case amount of response producers can grow limitless and cause
> OutOfMemoryException, so, this approach is not acceptable, too.
> 
> Can somebody explain, which is a proper way to implement asynchronous
> handler, which content is being generated by separate thread?
> Unfortunately, I was unable to find any hints on this in source code.
> 

Dmitry,

Whenever one ends up mixing transport code based on a non-blocking i/o
and processing code based on inherently blocking InputStream /
OutputStream API things are bound to get very ugly. 
 
Generally one must not invoke any potentially blocking code from either
request handler, request consumer or response producer (or basically any
routine executed by an I/O dispatch thread) or risk blocking all
connections managed by that thread. Therefore making a call
Executor#execute() from a I/O dispatch thread is a very risky
proposition unless the executor is backed by an unbounded thread pool. 

My recommendation would be to use an unbounded thread pool for
simplicity, but to make sure it shrinks automatically when load gets
lighter. If you are absolutely sure you want to use a fixed number of
worker threads to process an arbitrary of number of concurrent requests
you need to queue HttpAsyncExchange instances and employ an additional
thread to distribute them across a bounded pool of worker threads. To
sum it all up, whatever you do you want to make sure it is done without
blocking on a mutex longer than absolutely necessary.  

You can have a look at the CXF async client HTTP екфтызщке as an example
[1]. It is client side but the general approach should be applicable to
the server side as well.

Hope this helps somewhat. I'll happily deal with any follow-up questions
tomorrow.

Олег

[1]
http://svn.apache.org/repos/asf/cxf/trunk/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/
 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org


Mime
View raw message