You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by "lhotari (via GitHub)" <gi...@apache.org> on 2026/09/15 11:12:38 UTC

[PR] [improve][misc] Reduce executor queue allocation with growable arrays [pulsar]

lhotari opened a new pull request, #26588:
URL: https://github.com/apache/pulsar/pull/26588

   ### Motivation
   
   Client internal/listener executors and several lifecycle-managed server executors use `Executors.newSingleThreadExecutor`, allocating a linked queue node for queued tasks. High-fanout profiling identified executor queue allocation as a substantial consumer cost. A shared factory allows server components to reuse the array queue while opting out of GC cleanup when they explicitly manage shutdown.
   
   ### Modifications
   
   - Add `PulsarExecutors.newSingleThreadExecutor()` and its `ThreadFactory` overload in pulsar-common, backed by the existing `GrowableArrayBlockingQueue`. Update client `ExecutorProvider` to use this reusable factory, preserving lazy worker creation, thread factory, FIFO task execution and unbounded admission.
   - Add a `newSingleThreadExecutor(ThreadFactory, boolean autoShutdownOnGc)` overload. Existing overloads enable GC cleanup; explicitly managed components can pass false to use a non-GC unconfigurable facade without Cleaner registration.
   - Nest a package-private `AbstractExecutorService` facade inside `PulsarExecutors` that prevents executor reconfiguration and retains automatic graceful shutdown through a shared Cleaner. The cleanup action captures only the underlying executor; reachability fences protect admission and lifecycle operations.
   - Implement both queue `toArray` overloads through the existing locked snapshot. `ThreadPoolExecutor.shutdownNow` needs this fallback when an offer completes after its initial drain.
   - Migrate eight lifecycle-managed server executors with GC cleanup disabled: ModularLoadManagerImpl, AbstractMetadataStore, PulsarZooKeeperClient, PulsarLedgerUnderreplicationManager, JavaInstance, ProducerCache, BatchSourceExecutor and LeaderService. Preserve their thread factories and shutdown paths. Test code is not migrated.
   - Add lifecycle and queue snapshot/shutdown-race coverage, plus a JMH comparison of the actual client provider against the JDK single-thread executor.
   
   Tradeoffs: the array retains its peak capacity until the executor is released, and the facade adds a shared Cleaner daemon per loaded class. Scheduled executors keep their existing implementation. Review should focus on cleanup reachability, worker replacement, shutdown races and retained capacity.
   
   ### Verifying this change
   
   - [ ] Make sure that the change passes the CI checks.
   
   Passed locally:
   
   ```sh
   ./gradlew spotlessCheck checkstyleMain checkstyleTest
   ./gradlew quickCheck
   ./gradlew :pulsar-common:test --tests '*GrowableArrayBlockingQueueTest'
   ./gradlew :pulsar-common:test --tests '*PulsarExecutorsTest'
   ./gradlew :pulsar-client-original:test --tests '*PulsarClientImplTest.testInitializingWithExecutorProviders'
   ./gradlew :microbench:shadowJar
   ```
   
   All 19 scoped tests passed without retries: 11 queue cases, seven executor lifecycle/bulk-method cases covering both GC-cleanup modes, and shared-client provider initialization. The shutdown-race test injects a late queue offer at the drain boundary. Cleaner behavior is exercised deterministically through the registered cleanup action; this does not prove all GC/concurrency interleavings.
   
   JMH results for this change (8 submitting threads, two forks, 3 warmup/5 measurement iterations of 1 second, 512 MiB G1, `-prof gc`):
   
   | Tasks per batch | JDK allocation | Pulsar allocation | Reduction |
   |---|---:|---:|---:|
   | 16 | 549.78 B/batch | 161.40 B/batch | 70.6% |
   | 256 | 6,668.21 B/batch | 481.02 B/batch | 92.8% |
   
   Measured time was 23.43→21.73 us/batch and 276.72→259.70 us/batch, respectively. The host reached 100C with core/package throttle deltas 51/1402; these timings are not a reliable portable speedup claim. The benchmark includes submission and completion of a batch, not message delivery.
   
   ```sh
   java -jar microbench/build/libs/microbench-5.0.0-SNAPSHOT-benchmarks.jar \
     '.*ExecutorHandoffBenchmark.submitAndComplete' \
     -p executorType=jdk,pulsar -p tasksPerBatch=16,256 -t 8 -f 2 \
     -wi 3 -i 5 -w 1s -r 1s -jvmArgs '-Xms512m -Xmx512m -XX:+UseG1GC' -prof gc
   ```
   
   Server migration validation also passed 48 existing test invocations without retries or skips: ProducerCacheTest, JavaInstanceTest, BatchSourceExecutorTest, LeaderServiceTest, MetadataStoreTest notification/closed-store cases across providers, ledger replication re-enable callbacks across providers, ZooKeeper watcher recovery, and ModularLoadManagerImpl broker-stop cache updates. Full Spotless and main/test Checkstyle passed after migrating the eight production call sites. No server-side test sources were migrated or edited.
   
   Earlier integration profiling of the executor implementation showed 12.5% lower weighted consumer allocation (13.4% lower surviving-thread allocation counters) under rate-capped Key_Shared fanout. That is supporting evidence on an older upstream baseline, not a new measurement against current master. No maximum-throughput gain is claimed.
   
   ### Does this pull request potentially affect one of the following parts:
   
   - [ ] Dependencies (add or upgrade a dependency)
   - [x] The public API
   - [ ] The schema
   - [ ] The default values of configurations
   - [x] The threading model
   - [ ] The binary protocol
   - [ ] The REST endpoints
   - [ ] The admin CLI options
   - [ ] The metrics
   - [ ] Anything that affects deployment
   
   Adds the PulsarExecutors utility factory in pulsar-common. Executor queue and cleanup implementation change; task affinity and single-worker scheduling remain the same.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [improve][misc] Reduce executor queue allocation with growable arrays [pulsar]

Posted by "nodece (via GitHub)" <gi...@apache.org>.
nodece merged PR #26588:
URL: https://github.com/apache/pulsar/pull/26588


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org