Add an opt-in virtual threads flag for blocking I/O thread pools on Java 25 - #9097
Open
GGraziadei wants to merge 1 commit into
Open
GGraziadei wants to merge 1 commit into
GGraziadei wants to merge 1 commit into
Conversation
Introduce storm.virtual.threads.enabled (default false) and StormThreadFactory, which returns a virtual-thread ThreadFactory when the flag is on and a non-daemon, normal-priority platform-thread factory otherwise. Thread names are <prefix>-<n> in both modes. The factory is injected into the existing pools, so core sizes, queues, rejection policy and error handling are unchanged and the *.threads settings keep their meaning as a concurrency bound: - Thrift server handlers for the SASL, TLS and simple transports (Nimbus, Supervisor and DRPC). With the simple transport an executor is now always supplied when the flag is on; without a configured queue size it uses the same unbounded queue THsHaServer builds by default. - AsyncLocalizer download and task executors. - Nimbus AssignmentDistributionService and Supervisor heartbeat pools. - DRPCSpout background executor. - Worker shared executor exposed through TopologyContext, read from the merged topology conf so a topology can override the flag. Spout/bolt executor threads, worker transfer, JCQueue, Netty and timer threads are deliberately left on platform threads. Round-trip tests through NimbusClient assert that Thrift handlers run on virtual threads when the flag is on and on platform threads by default; unit tests cover the factory, the localizer executor and the worker shared executor. ThriftHandlerVirtualThreadsBench in storm-perf measures the flag against an in-process Nimbus Thrift server whose handler simulates blocking I/O. At equal *.threads the throughput is unchanged, while server-side OS threads drop from *.threads to roughly the number of cores.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is the purpose of the change
Now that master requires Java 25, this change lets operators opt in to Java virtual threads for Storm's blocking, I/O-bound thread pools through a new cluster setting,
storm.virtual.threads.enabled(defaultfalse). With the flag off nothing changes apart from thread names.A new helper,
org.apache.storm.utils.StormThreadFactory, returns a virtual-threadThreadFactorywhen the flag is on and a non-daemon, normal-priority platform-thread factory otherwise. The factory is injected into the existing pools, so core sizes, queues, rejection policy and error handling are untouched and the*.threadssettings keep their meaning as a concurrency bound:THsHaServerbuilds by default.AsyncLocalizerdownload and task executors.AssignmentDistributionServiceand Supervisor heartbeat pools.DRPCSpoutbackground executor.TopologyContext, read from the merged topology conf so a topology can override the flag.Spout/bolt executor threads, worker transfer, JCQueue, Netty event loops and timers are deliberately left on platform threads: they are busy-poll hot loops that would lose throughput on virtual threads.
The javadoc of the new key documents the operational caveats: all virtual threads share one carrier scheduler sized to the core count, blocking file I/O (blob downloads) occupies a carrier, and with the simple transport and no configured queue size the effective handler concurrency goes from
THsHaServer's fallback of 5 to*.threads.What the benchmark shows
ThriftHandlerVirtualThreadsBench(added toexamples/storm-perf) runs an in-process Nimbus Thrift server whose handler simulates blocking I/O and hammers it with N clients, each mode in its own JVM. On a 20-core machine:*.threads/ io-msAt equal
*.threadsthe throughput is unchanged (within a few percent) because the workload is bounded by the configured concurrency either way. The gain is in resources: server-side OS threads drop from*.threadsto roughly the number of cores, and RSS drops at high concurrency. The tail latency grows slightly at very high concurrency. In short, this is a resource saving on the control plane that lets operators raisenimbus.thrift.threads/supervisor.thrift.threadsto absorb bursts without paying for native threads; with the shipped defaults it is neutral, and it is off by default.How was the change tested
StormThreadFactoryTest(flag on/off/missing/unexpected type, thread naming, forcedNORM_PRIORITY),WorkerStateTest(shared executor on virtual vs platform threads),AsyncLocalizerTest(download executor on virtual vs platform threads).AuthTestthrough a realThriftServerandNimbusClient, asserting from inside the Nimbus handler that it runs on a virtual thread when the flag is on (simple transport with and without a queue size, digest SASL transport) and on a platform thread by default; the digest case also checksReqContextstill carries the principal on a virtual handler thread.storm-clientandstorm-serversuites pass with the flag off (default): 650 and 487 tests respectively, 0 failures.-Dstorm.options=storm.virtual.threads.enabled=true:LocalNimbusTestpasses and the "platform thread by default" assertion inAuthTestfails as expected, proving the flag reaches the handler pool.