Skip to content

[improve][broker] Avoid read locks in Key_Shared consumer selection - #26591

Merged
merlimat merged 1 commit into
apache:masterfrom
lhotari:lh-perfopt-improve-key-selector-review
Sep 15, 2026
Merged

merlimat merged 1 commit into
apache:masterfrom
lhotari:lh-perfopt-improve-key-selector-review

Conversation

@lhotari

@lhotari lhotari commented Sep 15, 2026

Copy link
Copy Markdown
Member

Motivation

ConsistentHashingStickyKeyConsumerSelector.select acquires a shared read lock and searches a tree for every selection. Consumer membership changes much less frequently than messages are dispatched, so the lookup can use a precomputed representation that avoids the read lock.

Modifications

  • Publish a snapshot of sorted hash points and their selected consumers after each membership update. Each lookup captures one volatile snapshot and uses binary search, preserving inclusive ceiling lookup, wraparound and empty-ring behavior.
  • Keep membership changes, collision handling and assignment reporting under the existing locks. The snapshot arrays are never modified after publication; concurrent lookups observe a complete old or new mapping.
  • Add boundary, collision and concurrent-membership tests, and a benchmark covering both selection and membership updates.

The snapshot retains an additional array representation of the ring and moves copying work to membership updates. This favors stable membership over frequent consumer churn.

Verifying this change

  • Make sure that the change passes the CI checks.

Passed locally: spotlessCheck checkstyleMain checkstyleTest, quickCheck, benchmark packaging, and 20 scoped test invocations with no failures or retries:

  • ConsistentHashingStickyKeyConsumerSelectorTest (14 cases).
  • KeySharedSubscriptionTest.testOrderingWhenAddingConsumers, testRemoveFirstConsumer and testCheckConsumersWithSameName (six invocations).

KeySelectorLookupBenchmark uses the actual selector with 100 hash points per consumer and impact reporting enabled. Two forks, three warmup/five measurement iterations of one second, one thread, 512 MiB G1 and the GC profiler:

Operation Consumers Before After
Select 2 50.65 ns 34.95 ns
Select 50 121.74 ns 56.55 ns
Add/remove pair 2 53.85 us 55.19 us
Add/remove pair 50 327.76 us 435.51 us

At 50 consumers, an add/remove pair allocates about 78 KB more. Both runs reached 100°C with thermal throttling, so these component timings do not establish a portable speedup or broker throughput gain. Local concurrency tests supplement the immutable-snapshot publication argument; they cannot prove every possible interleaving.

Does this pull request potentially affect one of the following parts:

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

Selection uses volatile snapshot publication instead of the membership read lock. Membership mutation remains serialized; public APIs and dispatch ordering contracts are unchanged.

@merlimat
merlimat merged commit 0fbe18c into apache:master Sep 15, 2026
44 checks passed
@lhotari lhotari added this to the 5.0.0 milestone Oct 1, 2026
Radiancebobo pushed a commit to Radiancebobo/pulsar that referenced this pull request Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants