Skip to content

[improve][broker] Speed up auto-split Key_Shared consumer selection - #289

Open
lhotari wants to merge 1 commit into
lh-perfopt-iot-performance-toolsfrom
lh-perfopt-auto-split-selector-snapshot
Open

lhotari wants to merge 1 commit into
lh-perfopt-iot-performance-toolsfrom
lh-perfopt-auto-split-selector-snapshot

Conversation

@lhotari

@lhotari lhotari commented Sep 19, 2026

Copy link
Copy Markdown
Owner

Motivation

The AUTO_SPLIT Key_Shared selector performs a ConcurrentSkipListMap.ceilingEntry lookup for every dispatched message. Consumer membership changes are rare compared with message selection, and those changes are already serialized. A concurrent ordered-map traversal therefore adds pointer chasing and comparison work to the hot path while membership is stable.

Modifications

  • Keep the existing maps as the authoritative membership and range-assignment state.
  • After each successful synchronized membership change, publish an immutable snapshot containing sorted primitive range ends and their consumers.
  • Select consumers by binary-searching one volatile snapshot read.
  • Add exhaustive assignment-equivalence coverage after additions and removals, concurrent selection/membership-churn coverage, and an actual-selector microbenchmark.

A selection concurrent with a membership change observes either the complete old snapshot or the complete new snapshot. Once addConsumer or removeConsumer returns, the new snapshot has been published.

Performance

JMH compares the actual selector with the previous ConcurrentSkipListMap.ceilingEntry lookup. Runs used two forks, three 1-second warmups, five 1-second measurements, and GC profiling.

Consumers Readers Before After Change
2 1 7.098 ns/op 3.745 ns/op -47.2%
10 1 9.863 ns/op 4.849 ns/op -50.8%
10 4 14.566 ns/op 5.189 ns/op -64.4%
50 1 13.842 ns/op 5.681 ns/op -59.0%
50 4 17.089 ns/op 6.760 ns/op -60.4%

Both implementations allocate effectively zero on selection. Membership changes allocate the compact snapshot and remain control-plane operations.

A five-million-message scenario with 500 producers and five ten-consumer Key_Shared subscriptions produced two positive matched comparisons:

Pair Before After Change
1 59,312 msg/s 74,128 msg/s +25.0%
2 59,779 msg/s 72,396 msg/s +21.1%

Every run delivered all messages to every subscription with zero duplicates, ordering violations, or invalid messages. The whole-host gain is larger than the isolated nanosecond saving directly explains, so the table establishes repeatability and absence of regression rather than attributing the full improvement to this lookup.

Verifying this change

This change added tests and can be verified as follows:

  • Exhaustive selection equivalence across the complete test hash range after every add and remove
  • Concurrent selection during repeated consumer membership changes
  • Existing selector test suite
  • ./gradlew :microbench:shadowJar quickCheck
  • Two matched end-to-end scenario pairs with ordering and duplication checks

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

@lhotari
lhotari force-pushed the lh-perfopt-auto-split-selector-snapshot branch from 494712e to 0d02248 Compare September 19, 2026 12:20
@lhotari
lhotari changed the base branch from lh-perfopt-auto-split-selector-base to lh-perfopt-iot-performance-tools September 19, 2026 12:21
@lhotari
lhotari force-pushed the lh-perfopt-iot-performance-tools branch from 6c31d73 to b7456bd Compare September 19, 2026 12:35
@lhotari
lhotari force-pushed the lh-perfopt-auto-split-selector-snapshot branch from 0d02248 to d949d8c Compare September 19, 2026 12:35
@lhotari
lhotari force-pushed the lh-perfopt-iot-performance-tools branch from b7456bd to c2926ee Compare September 19, 2026 12:37
@lhotari
lhotari force-pushed the lh-perfopt-auto-split-selector-snapshot branch from d949d8c to ab34a61 Compare September 19, 2026 12:38
@lhotari
lhotari force-pushed the lh-perfopt-iot-performance-tools branch from c2926ee to e676723 Compare September 19, 2026 12:42
@lhotari
lhotari force-pushed the lh-perfopt-auto-split-selector-snapshot branch from ab34a61 to 651dda1 Compare September 19, 2026 12:42
Publish an immutable lookup snapshot after membership changes so the hot selection path uses primitive-bound binary search instead of a concurrent skip-list lookup.

Assisted-by: Codex
@lhotari
lhotari force-pushed the lh-perfopt-iot-performance-tools branch from e676723 to 5d78280 Compare September 19, 2026 12:47
@lhotari
lhotari force-pushed the lh-perfopt-auto-split-selector-snapshot branch from 651dda1 to 99c5d57 Compare September 19, 2026 12:47
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.

1 participant