-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decouple QTP idleTimeout
from pool shrink rate
#9237
Comments
What is exactly the problem this enhancement would address? I understand you would like to shrink the thread pool more aggressively, but why exactly? |
In the particular case I'm dealing with, the "idle threads are cheap" assumption does not hold. We're using Solr, and under the hood Lucene has historically used ThreadLocal caching in some cases. This is fixed in the most recent Lucene version, so the problem will be best addressed in time by avoiding pathological usage of ThreadLocal caching. That said, I'm raising this issue here because in principle I think it's probably the right thing to do to allow configuring pool decay in a way that's independent from individual thread A little more detail/context: we see certain isolated events that generate a spike in thread count (from ~2k baseline to ~4k or higher). Ideally we don't want to reduce the Again, I'm not really trying to "solve" this problem -- the underlying problem is not a problem with Jetty (this is why my initial description was a bit vague wrt the motivating case -- sorry!). But it's a problem that at a high level ("threads are not always cheap") is not unique to this situation, and that could I believe be readily worked around by decoupling |
What specifically are you worrying about? This seems like worrying about memory usage of idle threads. (which can be addressed in different ways) |
Exactly; for my particular case this is the essence of the problem, and without a doubt the best/right way to deal with the situation is to eliminate reliance on ThreadLocal caching. Are there ways to address memory usage of idle threads, beyond "prevent included libraries from accessing ThreadLocal storage"? That's the right approach, but there are cases where it's hardly practical, and in the immediate term (in cases without influence over included libraries) may be effectively impossible. My particular problem will in time be solved in another way. I'm raising this issue here mainly on principle, because:
|
The memory usage of a thread is determined by it's stack depth. The JVM supports configurations to limit this and reduce the memory load of threads overall. See:
Note also that Java 8 is worse than Java 11 which is worse than Java 17 when it comes to memory use for threads. |
No. For platform threads, this is set by default at 1 MiB, independently from the stack depth. It's often unpractical to specify |
Thank you both for your feedback/consideration! Indeed, on-heap ThreadLocal concerns are in addition to any JVM-level or system level impacts from persistent high thread count. It would be fantastic to have this addressed going forward; I'm happy to offer assistance, to whatever extent that would be helpful. |
Just a quick check-in to make sure this doesn't fall off the radar. If you're interested in moving forward with this enhancement, are there any open questions/concerns with the approach proposed? Any things to keep in mind if I were to try to update the proposed implementation to make it suitable for contribution? |
I like the idea of having an additional configuration parameter that reduces the number of threads in case they are idle. However, a "shrinkInterval" does not seem very intuitive to me... I think I prefer a "count" but not sure how would that be implemented. Keep pushing on this feature request, but understand that's not super-high priority. |
Perfect, thanks! One of the reasons I went with Here's a thought: rather than force users to manually specify an absolute Running with this idea a bit: it'd be a natural fit to map 1 => " |
How about having a boolean flag |
@sbordet, after some consideration, I think your suggestion to have the API deal with " I've pushed a new commit that illustrates this approach. The tricky thing implementation-wise is that the threads independently expire themselves, so any approach to expiring may neither be truly "batched" (expire N threads once per X interval) nor "linear" (expire N threads evenly spread across X interval). The commit above does a very simple conversion of |
This is looking plausible.... can you make a draft PR so that we can use the tools to review/modify it? |
Introduced `QueuedThreadPool.idleTimeoutMaxShrinkCount` to be the number of idle threads that are exited in one idle timeout. When set to 1 (the default), the old behavior is reproduced: expiring 1 thread every idle timeout. When set to larger values, allows to keep around the threads for the idle timeout (in case of further load spikes), but allows to quickly recover OS memory when they are truly idle. For example, with 2000 threads, 30 seconds idle timeout and idleTimeoutMaxShrinkCount=1, it will take 995 minutes (about 16.5 hrs) to shrink the pool back to 10 threads. By setting idleTimeoutMaxShrinkCount=100, the thread pool can be shrunk to 10 threads in about 10 minutes. Signed-off-by: Simone Bordet <[email protected]>
Signed-off-by: Ludovic Orban <[email protected]>
Signed-off-by: Ludovic Orban <[email protected]>
…eout period should be observed or not Signed-off-by: Ludovic Orban <[email protected]>
…ch block and that the interrupt flag is always cleared when it returns, also make aggressive shrinking the only possibility Signed-off-by: Ludovic Orban <[email protected]>
Signed-off-by: Ludovic Orban <[email protected]>
Signed-off-by: Ludovic Orban <[email protected]>
… minThread + comment why that's safe Signed-off-by: Ludovic Orban <[email protected]>
… minThread + comment why that's safe Signed-off-by: Ludovic Orban <[email protected]>
…e at least one idleTimeout period without shrinking Signed-off-by: Ludovic Orban <[email protected]>
…e at least one idleTimeout period without shrinking Signed-off-by: Ludovic Orban <[email protected]>
Enhancement Description
It should be possible to independently configure the rate at which QueuedThreadPool, having seen a transient spike in number of threads, shrinks back to a normal/baseline number of threads.
This issue has been raised several times; #4585 provides excellent context.
Afaict, this comment sums up the current approach:
This makes sense when idle threads are guaranteed to be cheap. For the purpose of this issue, let's acknowledge that this should always be the case, and that cases where persistently large thread pools result in a bottleneck on system resources are arguably better addressed in some other way.
Even acknowledging the above however, it still makes sense in principle to decouple the rate of pool shrinkage from the amount of time that individual threads are allowed to remain idle before being eligible to be reclaimed.
Paraphrasing from this comment (I think the math in the original comment was inverted!):
This is a good example of the options currently available; but I'd argue there's a significant difference between the alternatives suggested. There's obviously no difference at the 60000ms mark: starting with 100 idle threads, each alternative would hit 0 threads at 60s. But notably, the first option would retain all 100 threads all the way out to the 60s point, and would thus be better able to respond to certain types of bursty traffic.
For the purpose of discussion I pushed a single commit that I think should address this.
The text was updated successfully, but these errors were encountered: