Hi Greg

Thank you very much for your suggestions, they're really useful.

Yes - I was thinking that we need to limit the total number of threads, as each 
of them can use a lot of memory. I guess we could increase the thread pool size 
to something large, and put a fair semaphore around the actual work. After 50ms 
work is done, a startAsync followed by an immediate redispatch would, I think, 
preserve the behaviour of ThreadLimitHandler - particularly that requests from 
a single client remain interleaved, due to the FIFO queue per Remote. (correct 
me if I'm wrong!)

I should also have mentioned that writing the response (and reading from disk) 
is much of the work of each 50ms chunk. I guess it's something like a file 
server. So the clients (which are generally not browsers) aren't waiting 
minutes for the HTTP headers, and we need to stream the response (as they can 
be very large).

With the concurrent queue idea, I guess after each chunk of work, you could 
always add yourself to the back of the queue and dispatch a request from the 
front (which could be yourself - in that case it doesn't matter that you're 
hogging a thread). You'd also need to reserve one thread to accept new 
requests, which are immediately put on the queue (so no blocking work is done). 
(I think you'd also need a reserved thread in your suggestion?)

Agreed that (assuming you agree with it) the non-async approach is probably 
better. (It's also clearly better than a separate thread pool!)

Best

Matt

________________________________
From: jetty-users-boun...@eclipse.org <jetty-users-boun...@eclipse.org> on 
behalf of Greg Wilkins <gr...@webtide.com>
Sent: 01 June 2020 13:31
To: JETTY user mailing list <jetty-users@eclipse.org>
Subject: Re: [jetty-users] Interleaving requests for fairness/starvation?

Matt,

Are you doing this to try to limit the total threads, or just to make sure that 
some threads are not starving others?   If you don't mind the total number of 
threads, then you could simply put in a Thread.yield() call every 50ms and not 
worry about async servlet handling.

Note also, from a users perspective, having requests that can take many minutes 
to respond is not great.  If your clients are browsers, then it could be better 
to separate your handling from the request/response thread - ie start the 
handling and then immediately respond. Your clients could then poll (or better 
yet long poll) to see progress and to get the final state.

I'm very cautious about any approach that changes the behaviour of the 
threadpool, especially tryExecute.  The behaviour there is all very finely 
tuned to our scheduling strategies to avoid deadlocks and thread starvation.

If you do want to use servlet async to do the interleaving, you need to get 
other requests/threads to do the dispatching.  EG every 50ms of processing your 
app can look at a concurrent list to see if other processes are waiting to be 
handled, if they are, then dispatch the first of them then  start async and add 
your AsyncContext to the end of the queue.  The problem with this approach is 
how does the first request ever get added to the queue?  Perhaps you need a 
limit on concurrent handling as well and if you are above that, add yourself to 
the queue... if you finish handling and reduce the handling count below the 
threshhold, then you can also wakeup any waiting contexts on the queue.      
This is making Thread.yield feel very simple.

cheers





On Mon, 1 Jun 2020 at 13:51, Matthew Boughen 
<knabb...@live.co.uk<mailto:knabb...@live.co.uk>> wrote:
Hi

I was wondering if anyone could confirm whether what we've done is sensible - 
it seems to work, but I'm not really confident and would like to know how 
righteous it is!

Our HTTP server processes requests that can take minutes at a time, the 
handling for which can easily be broken down into small chunks. We would like 
to interleave the handling of these requests so that none get starved and time 
out (and to help with fairness). For each request, after 50ms of handling, we 
asynchronously suspend the request and (hope to) redispatch it to the queue 
behind newly arrived requests / other more-recently suspended requests.

With this approach, the issue seems to be in choosing where to call 
asyncContext.dispatch: too close to the suspend call (startAsync) and Jetty 
will not release the thread back to allow processing of other queued requests 
(presumably because Jetty thinks it's more efficient to avoid the context 
switch and so immediately continues processing the current request).

We've currently settled on overriding QueuedThreadPool.execute(Runnable) and 
tryExecute(Runnable) to wrap the Runnable: any request that had registered 
itself while the original (unwrapped) Runnable was called is now redispatched. 
This seems to work in that: (a) only one request attempts to register itself 
each time a Runnable is run, (b) the redispatch normally seems to happen very 
quickly after the request has registered itself, and (c) the request handling 
is indeed interleaved.

Does that sound like the right thing to do here? I'm thinking it would be as 
long as each request handle is guaranteed to be the tail call of a task 
submitted to the thread pool (I don't know enough about the use of 
ExecutionStrategy to know this).

Any suggestions/comments are highly appreciated.

Matt


P.S. I'm anticipating that the right thing to do might be to use a separate 
thread pool and manage the interleaving there? This of course would incur 
another thread context switch / managing another pool. We're also using 
ThreadLimitHandler to avoid single clients taking out the whole server, so 
would need to duplicate that logic.

_______________________________________________
jetty-users mailing list
jetty-users@eclipse.org<mailto:jetty-users@eclipse.org>
To unsubscribe from this list, visit 
https://www.eclipse.org/mailman/listinfo/jetty-users


--
Greg Wilkins <gr...@webtide.com<mailto:gr...@webtide.com>> CTO 
http://webtide.com
_______________________________________________
jetty-users mailing list
jetty-users@eclipse.org
To unsubscribe from this list, visit 
https://www.eclipse.org/mailman/listinfo/jetty-users

Reply via email to