Skip to content

Assign a distinct event loop to each virtual thread verticle instance - #6313

Open
jnbdz wants to merge 1 commit into
eclipse-vertx:masterfrom
SiteNetSoft:issue-5924-vthread-eventloop-distribution
Open

Assign a distinct event loop to each virtual thread verticle instance#6313
jnbdz wants to merge 1 commit into
eclipse-vertx:masterfrom
SiteNetSoft:issue-5924-vthread-eventloop-distribution

Conversation

@jnbdz

@jnbdz jnbdz commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Motivation

Deploying a verticle with setInstances(N) and ThreadingModel.VIRTUAL_THREAD pins every instance to the same event loop, so raising the instance count does not scale I/O — the single event loop saturates while the virtual threads starve. The reporter measured a hard ceiling of ~40k RPS with setInstances(300), against ~180k RPS when the instances were spread over the event loop group.

Fixes #5924

Why this looks unintended rather than by design

The shared event loop comes from 7045785, which changed WORKER and VIRTUAL_THREAD in the same diff. Its rationale is stated entirely in terms of worker verticles:

As consequence a worker server will be scaled on that number of event-loop while being processed on the same number of workers. There is no strong interest for this use case and a single event-loop might actually work better and consume less resources.

That reasoning holds for workers, where the work is dispatched to the worker pool. It does not transfer to the virtual thread model, where the event loop still carries the I/O for everything the verticle creates and there is no separate pool absorbing the load. The virtual thread branch appears to have been carried along with the worker change rather than considered on its own.

For reference, 4.x built a context per instance for both models, each picking eventLoopGroup.next().

Change

Build a fresh context for each virtual thread instance, so each one round-robins over the event loop group like the event-loop model already does. workerLoop is now used only by the WORKER branch, which keeps its current behaviour and its testWorkerInstancesUseSameEventLoopThread assertion.

Test

io.vertx.tests.virtualthread.DeploymentTest#testInstancesUseDistinctEventLoopThreads deploys 4 virtual thread instances over an 8 loop pool and asserts 4 distinct event loop threads. It fails on the current code (expected:<4> but was:<1>) and passes with the change. The pool is sized from the instance count so the assertion does not depend on the host's core count.

Verified on JDK 21: the full vertx-core-java21-tests module (241 tests), plus DeploymentTest (73), ContextTest (66) and VertxTest (19) in vertx-core, all green.

Note

@vietj you suggested on the issue that this could be made configurable, and the commit above anticipated "a setting to control this". This PR restores the scaling default for the virtual thread model only, on the reading that the worker rationale never applied to it. If you would rather express it as a DeploymentOptions setting — defaulting either way — I am happy to rework it in that direction.

This supersedes #6241, which proposed the same change and was closed by its author.

Motivation:

Deploying a verticle with setInstances(N) and ThreadingModel.VIRTUAL_THREAD
pins every instance to the same event loop, so raising the instance count
does not scale I/O: the single event loop saturates while the virtual
threads starve. Vert.x 4.x assigned an event loop per instance via
eventLoopGroup.next().

The shared event loop was introduced for worker verticle deployments, where
the work happens on the worker pool and a single event loop consumes fewer
resources. The virtual thread model was changed at the same time, although
that rationale does not apply to it.

Changes:

Build a fresh context for each virtual thread instance so that each one
round-robins over the event loop group, like the event-loop model does.
The shared event loop remains for worker deployments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant