Skip to content

Add virtual thread support for gRPC and HTTP servers on JDK 25+#13705

Open
wu-sheng wants to merge 5 commits intomasterfrom
virtual-threads
Open

Add virtual thread support for gRPC and HTTP servers on JDK 25+#13705
wu-sheng wants to merge 5 commits intomasterfrom
virtual-threads

Conversation

@wu-sheng
Copy link
Member

@wu-sheng wu-sheng commented Feb 16, 2026

Add virtual thread support for gRPC and Armeria HTTP server handler threads (JDK 25+)

  • If this is non-trivial feature, paste the links/URLs to the design doc.
  • Update the documentation to include this new feature.
  • Tests(including UT, IT, E2E) are added to verify the new feature.
  • If it's UI related, attach the screenshots below.

Design summary:

Uses runtime reflection to detect JDK 25+ virtual thread APIs — zero compile-time
dependency, fully backward compatible with JDK 11/17/21. JDK 25 is required (not 21)
because JDK 21-23 has a critical synchronized pinning bug fixed by
JEP 491 in JDK 24, and JDK 25 is the first LTS with
that fix.

Thread Pool JDK < 25 (unchanged) JDK 25+
gRPC server handler (core-grpc) Cached platform threads (unbounded) Virtual threads (per-task)
HTTP blocking (core-http, receiver-http, promql-http, logql-http, zipkin-query-http, zipkin-http, firehose-http) Cached platform threads (max 200/server) Virtual threads (per-task)
Netty/Armeria I/O event loops Platform threads Unchanged

On JDK 25+, all gRPC/HTTP handler pools share ~9 ForkJoinPool carrier threads instead
of up to 800+ platform threads.

Key components:

  • VirtualThreads — reflection-based detection & executor factory
  • VirtualThreadScheduledExecutor — wraps virtual threads as ScheduledExecutorService for Armeria
  • Docker default image changed from JDK 11 to JDK 25; JDK 11/17/21 variants remain
  • Disable via SW_VIRTUAL_THREADS_ENABLED=false

wu-sheng and others added 4 commits February 16, 2026 15:08
Introduce VirtualThreads utility that enables virtual-thread-per-task
executors for all gRPC servers when running on JDK 25+, with automatic
fallback to platform thread pools on older JDKs. JDK 25 is required
as the first LTS with the synchronized pinning fix (JEP 491).

Each gRPC server gets a distinct thread pool name (core-grpc,
receiver-grpc, als-grpc, ebpf-grpc) for log identification, with
virtual threads prefixed by "vt:" in their names. A kill switch
(SW_VIRTUAL_THREADS_ENABLED=false) allows disabling virtual threads
at runtime. Also documents SW_OAL_ENGINE_DEBUG alongside the new
flag in configuration-vocabulary.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Armeria's blockingTaskExecutor (default max 200 cached platform threads
per server) runs all @Blocking handler methods. On JDK 25+, replace it
with a fully virtual-thread-backed ScheduledExecutorService.

VirtualThreadScheduledExecutor implements scheduling by sleeping in
virtual threads (which does not block OS threads), requiring zero
platform threads. VirtualScheduledFuture provides the ScheduledFuture
contract backed by virtual thread futures.

Each HTTP server gets a distinct name (core-http, receiver-http,
promql-http, logql-http, zipkin-query-http, zipkin-http, firehose-http).
Document thread pool changes in changes.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JDK 25 is now the default Docker image (eclipse-temurin:25-jre).
JDK 11 is kept as a -java11 variant, alongside existing -java17 and -java21.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wu-sheng wu-sheng added core feature Core and important feature. Sometimes, break backwards compatibility. enhancement Enhancement on performance or codes complexity:high Relate to multiple(>4) components of SkyWalking labels Feb 16, 2026
@wu-sheng wu-sheng added this to the 10.4.0 milestone Feb 16, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds virtual thread support for gRPC and HTTP server handler threads on JDK 25+, significantly reducing platform thread usage from 800+ threads to approximately 9 ForkJoinPool carrier threads. The implementation uses runtime reflection for backward compatibility with JDK 11/17/21, requiring JDK 25+ for virtual threads due to the critical synchronized pinning fix in JEP 491. The feature can be disabled via SW_VIRTUAL_THREADS_ENABLED=false.

Changes:

  • Introduced VirtualThreads utility with reflection-based JDK 25+ detection and executor factory methods
  • Created VirtualThreadScheduledExecutor to wrap virtual threads as ScheduledExecutorService for Armeria compatibility
  • Updated gRPC and HTTP servers across all receiver/query plugins to use virtual thread executors with descriptive names
  • Changed default Docker base image from JDK 11 to JDK 25, keeping JDK 11/17/21 as tagged variants
  • Added comprehensive documentation for the new environment variable and thread pool changes

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/VirtualThreads.java Core utility for creating virtual thread executors with reflection-based JDK 25+ detection
oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/VirtualThreadScheduledExecutor.java ScheduledExecutorService wrapper that delegates to virtual threads with sleep-based scheduling
oap-server/server-library/library-util/src/test/java/org/apache/skywalking/oap/server/library/util/VirtualThreadsTest.java Comprehensive tests for virtual thread executor creation and scheduling functionality
oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServer.java Updated gRPC server to use VirtualThreads.createExecutor() with descriptive thread pool names
oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/http/HTTPServer.java Updated HTTP server to use virtual thread scheduled executor for Armeria blocking tasks
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java Set thread pool names for core gRPC and HTTP servers
oap-server/server-receiver-plugin/zipkin-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zipkin/ZipkinReceiverProvider.java Set blocking task name for Zipkin HTTP receiver
oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java Set thread pool names for shared receiver HTTP and gRPC servers
oap-server/server-receiver-plugin/skywalking-ebpf-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/ebpf/provider/EBPFReceiverProvider.java Set thread pool name for eBPF gRPC receiver
oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java Set thread pool name for Envoy ALS gRPC receiver
oap-server/server-receiver-plugin/aws-firehose-receiver/src/main/java/org/apache/skywalking/oap/server/receiver/aws/firehose/AWSFirehoseReceiverModuleProvider.java Set blocking task name for AWS Firehose HTTP receiver
oap-server/server-query-plugin/zipkin-query-plugin/src/main/java/org/apache/skywalking/oap/query/zipkin/ZipkinQueryProvider.java Set blocking task name for Zipkin query HTTP server
oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/PromQLProvider.java Set blocking task name for PromQL HTTP server
oap-server/server-query-plugin/logql-plugin/src/main/java/org/apache/skywalking/oap/query/logql/LogQLProvider.java Set blocking task name for LogQL HTTP server
docs/en/setup/backend/configuration-vocabulary.md Documented SW_VIRTUAL_THREADS_ENABLED environment variable
docs/en/changes/changes.md Added changelog entry describing virtual thread support and thread pool changes
docker/oap/Dockerfile Changed default base image from eclipse-temurin:11-jre to eclipse-temurin:25-jre
.github/workflows/publish-docker.yaml Reordered Java 11 build step and removed explicit Java 25 variant (now default)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- List all 11 thread pools (4 gRPC + 7 HTTP) in changelog table
- Mention both gRPC and HTTP in SW_VIRTUAL_THREADS_ENABLED doc

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

complexity:high Relate to multiple(>4) components of SkyWalking core feature Core and important feature. Sometimes, break backwards compatibility. enhancement Enhancement on performance or codes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Upgrade to JDK/JVM25 to adopt ZGC and VirtualThread

1 participant