-
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
Fixes #8007 - Support Loom. #8035
Conversation
Implemented virtual threads support for HTTP/1.1, HTTP/2 and HTTP/3. Signed-off-by: Simone Bordet <[email protected]>
@gregw @lorban @joakime here is the proposal to support Loom. I have 2 concerns:
Thoughts? |
jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
Outdated
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
Outdated
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
Outdated
Show resolved
Hide resolved
jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java
Show resolved
Hide resolved
Updates after review. Signed-off-by: Simone Bordet <[email protected]>
Reworked this PR to have |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this is under analysed. Not exactly sure when virtual threads are being used and suspect they are being over-used. For example they should not be used for async callback.
We need to support this PR with benchmarks. I'd also like to see how this plays out in jetty-12, as we don't want to add a feature that will then be significantly different in 12.
@@ -34,18 +33,19 @@ public abstract class AbstractConnectionFactory extends ContainerLifeCycle imple | |||
{ | |||
private final String _protocol; | |||
private final List<String> _protocols; | |||
private int _inputbufferSize = 8192; | |||
private int _inputBufferSize = 8192; | |||
private boolean _useVirtualThreadToInvokeRootHandler; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think _useVirtualThreads
is sufficient for the name. Make it clear in the javadoc that we use virtual threads where appropriate to do so, specifically invoking root handler.
protected void execute(Runnable task) | ||
{ | ||
if (_httpConnection.isUseVirtualThreadToInvokeRootHandler()) | ||
{ | ||
if (VirtualThreads.startVirtualThread(task)) | ||
return; | ||
} | ||
super.execute(task); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this using virtual threads too much? It is certainly using them more than the claim in the current name of "InvokeRootHandler".
public void fillInterested() | ||
{ | ||
if (_readCallback != null) | ||
getEndPoint().fillInterested(_readCallback); | ||
else | ||
super.fillInterested(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels asymmetric and another "if" in critical path. Would be better to make the _readCallback in AbstractConnection extensible rather than duplicated.
I second @gregw 's comment as I fail to see what benefit virtual threads bring here in exchange for the added complexity. IMHO it's worth investigating from a side-branch, but not merging into any main branch for the moment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sbordet Thinking about this a bit more, all we need do is start using virtual threads for any fillInterest callback that are blocking.
This could be done at several levels:
- In Abstract connection we could replace the default blocking ReadCallback with a nonblocking version that starts a virtual thread. This would catch anything that just calls no args
fillInterest()
- Alternately, we could intercept in the
AbstractEndPoint#fillInterested(Callback)
method and any blocking callback passed is immediately wrapped in a non-blocking callback that uses virtual threads. - Or we could do the same in the FillInterested class itself
I think 1 is simplest and least cost, but 2 is probably a more thorough solution. Our execution strategy around the selector would then never ever see a blocking callback.
We could perhaps do the same on the write side... but I'm not sure we have many instances of blocking callbacks passed to a write?
@sbordet actually change that! The best place to do this is with a pluggable execution strategy (which we used to have??? still do???).
There can then be variations of that once we have pluggable strategies. |
@gregw I think in a different way, in the sense that if I deploy my webapps in Jetty and I want to enable Loom, I really want my applications to be called by a virtual thread. In your example above, if we have a reserved thread, then we use a native thread to call the application, and that would be unexpected. For example, AWS has a signing service - say give it bytes, it gives back a crypto signature - but it's a blocking AWS API call. So I think we must always invoke user code with a virtual thread if Jetty is configured so. So perhaps we tag the |
@sbordet application code should not care what kind of thread it gets. It can call the blocking aws call with either type. But if you really want that, then it's just a different execution strategy that doesn't use reserved threads. |
They actually do, it's the whole point of Loom. Call apps with a virtual thread, they can do blocking no problems. Otherwise they have to do non-blocking/reactive to scale.
You mean a strategy with reserved=0 and always executing using virtual threads? |
@sbordet, you've not understood my proposal. Application is able to block no matter what type of thread it is called by. All we have to to is ensure that the we don't use the last available real thread to call them, ie if no reserved threads then use a virtual thread to call the application. If all the real threads -1 end up blocked in the application, then no problem as virtual thread are used from them on, whilst last real thread does the producing. Less hot caches, but it still works. Or configure with 1 real thread to do the producing and every other thread will be virtual Either way, the solution is to have a pluggable strategy again. |
@gregw we're not on the same page. Loom is an application feature, not a server feature. We don't care about using Loom inside the server. We have to use Loom to call the application, no matter how many reserved threads we have, etc. |
agreed. We are not on the same page :) let's chat. |
Closed in favor of #8360. |
Implemented virtual threads support for HTTP/1.1, HTTP/2 and HTTP/3.
Signed-off-by: Simone Bordet [email protected]