Virtual vs platform performance at 10K HTTP requests
Alan Bateman
alan.bateman at oracle.com
Thu Nov 27 18:46:19 UTC 2025
On 27/11/2025 16:38, Cay Horstmann wrote:
> I did both with David's benchmark. Of course, the semaphore is the way
> to go. With default Tomcat settings, 200 or 2000 permits work fine,
> and then virtual threads give significantly better throughput than a
> small number of platform threads. As one would expect.
>
> But back to those 10000 simultaneous connections. As David observed,
> left unthrottled, virtual threads do really poorly. In my experiment,
> *much* more poorly than platform threads, when using a
> Executors.newCachedThreadPool().
10k or 50k+ concurrent connections shouldn't be an issue but it may
involve tweaking a number of sysctl.conf/equivalent settings to get
there. Elliot Barlas published a fun project at one point where he had
several million TCP connections with 2 virtual threads per connection.
I think the issue we are discussing here is partly about storming the
server with SYN packets to establish the TCP connections. Servers
typically have rate limiting and other mitigations to avoid SYN flood
attacks. This is why we were asking about the connection backlog and
other configuration. It's possible the thread pool bench isn't going to
see this because it's using synchronous/blocking APIs to establish the
TCP connection and so the number of outstanding connects in progress is
limited by the size of the thread pool.
The other part that seems relevant is that the protocol in the
benchmarks is HTTP/1.1 which supports persistent connections,
essentially re-use of a TCP connection if possible to avoid creating a
new TCP connection for each HTTP server. There's another layer of
configuration here. I don't know Tomcat's defaults but it is likely that
it keep 100 or 200 connections alive for future HTTP requests. Once the
concurrency exceeds this then it's likely there is a new TCP connection
established for each request. The thread pool bench is 4 threads and
likely well below the maximum number of persistent connections.
So yes, moving from thread pools to virtual threads may shine light on
the "next" concurrency bottleneck, the bottle hidden by limiting the
number of threads. The guidance that we've given at conferences and in
the JEPs is to use a semaphore/equivalent to limit concurrent at the
right level of granularity, be that number of concurrent database
connections or whatever it might be.
>
> I am wondering why that would be, and whether it is something that is
> worth addressing, because it seems like something that people could
> run into in practice. FWIW, I stumbled upon
> https://bugs.openjdk.org/browse/JDK-8360046 which addresses a somewhat
> similar scenario.
That one is an over subscription issue that arises with producer
starting a lot of virtual threads that "do nothing". It helps us to
reduce the gap between ForkJoinTasks that "do nothing" with virtual
threads that "do nothing".
-Alan
More information about the loom-dev
mailing list