You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add concurrency support to ShareKafkaMessageListenerContainer
Share consumers (KIP-932) enable record-level load balancing where
multiple consumers can cooperatively process from the same partitions.
Unlike traditional consumer groups with exclusive partition ownership,
share groups distribute work at the broker level via the share group
coordinator.
This commit adds native concurrency support to the existing
`ShareKafkaMessageListenerContainer` rather than creating a separate
`ConcurrentShareKafkaMessageListenerContainer`. This design choice
avoids the parent/child container complexity that exists in the regular
consumer model, since share consumers fundamentally operate differently:
- Work distribution happens at the broker level, not at the Spring layer
- Multiple threads simply provide more capacity for the broker to
distribute records across
- No partition ownership model to coordinate between child containers
This approach provides:
- Simpler architecture with a single container managing multiple threads
- No parent/child context propagation concerns
- Better alignment with share consumer semantics (record-level vs
partition-level distribution)
- Increased throughput for high-volume workloads
- Better resource utilization across consumer threads
Users can configure concurrency at three levels:
1. Per-listener via `@KafkaListener(concurrency = N)`
2. Factory-level default via `factory.setConcurrency(N)`
3. Programmatically via `container.setConcurrency(N)`
The feature works seamlessly with both implicit (auto-acknowledge) and
explicit (manual acknowledge/release/reject) acknowledgment modes, with
each consumer thread independently managing its own acknowledgments.
Signed-off-by: Soby Chacko <[email protected]>
The `ShareKafkaMessageListenerContainer` provides a simple, single-threaded container for share consumers:
110
+
The `ShareKafkaMessageListenerContainer` provides a container for share consumers with support for concurrent processing:
111
111
112
112
[source,java]
113
113
----
@@ -151,6 +151,145 @@ Share consumers do not support:
151
151
* Manual offset management
152
152
====
153
153
154
+
[[share-container-concurrency]]
155
+
=== Concurrency
156
+
157
+
The `ShareKafkaMessageListenerContainer` supports concurrent processing by creating multiple consumer threads within a single container.
158
+
Each thread runs its own `ShareConsumer` instance that participates in the same share group.
159
+
160
+
Unlike traditional consumer groups where concurrency involves partition distribution, share consumers leverage Kafka's record-level distribution at the broker.
161
+
This means multiple consumer threads in the same container work together as part of the share group, with the Kafka broker distributing records across all consumer instances.
162
+
163
+
==== Configuring Concurrency Programmatically
164
+
165
+
[source,java]
166
+
----
167
+
@Bean
168
+
public ShareKafkaMessageListenerContainer<String, String> concurrentContainer(
* **Thread Safety**: Each consumer thread has its own `ShareConsumer` instance and manages its own acknowledgments independently
236
+
* **Client IDs**: Each consumer thread receives a unique client ID with a numeric suffix (e.g., `myContainer-0`, `myContainer-1`, etc.)
237
+
* **Metrics**: Metrics from all consumer threads are aggregated and accessible via `container.metrics()`
238
+
* **Lifecycle**: All consumer threads start and stop together as a unit
239
+
* **Work Distribution**: The Kafka broker handles record distribution across all consumer instances in the share group
240
+
* **Explicit Acknowledgment**: Each thread independently manages acknowledgments for its records; unacknowledged records in one thread don't block other threads
241
+
242
+
==== Concurrency with Explicit Acknowledgment
243
+
244
+
Concurrency works seamlessly with explicit acknowledgment mode.
245
+
Each consumer thread independently tracks and acknowledges its own records:
public void processOrder(ConsumerRecord<String, String> record, ShareAcknowledgment acknowledgment) {
256
+
try {
257
+
// Process the order
258
+
processOrderLogic(record.value());
259
+
acknowledgment.acknowledge(); // ACCEPT
260
+
}
261
+
catch (RetryableException e) {
262
+
acknowledgment.release(); // Will be redelivered
263
+
}
264
+
catch (Exception e) {
265
+
acknowledgment.reject(); // Permanent failure
266
+
}
267
+
}
268
+
----
269
+
270
+
[NOTE]
271
+
====
272
+
**Work Distribution Behavior:**
273
+
274
+
With share consumers, record distribution is controlled by Kafka's share group coordinator at the broker level, not by Spring for Apache Kafka.
275
+
The broker may assign all records to a single consumer thread at any given time, especially when:
276
+
277
+
* The topic has a single partition
278
+
* There's low message volume
279
+
* The broker's distribution algorithm favors certain consumers
280
+
281
+
This is normal behavior. The key benefit of concurrency is having multiple consumer threads *available* to the share group coordinator for distribution.
282
+
As message volume increases or over time, you should see distribution across multiple threads.
283
+
284
+
This differs from traditional `ConcurrentMessageListenerContainer` where Spring explicitly distributes partitions across threads.
285
+
286
+
When using concurrency with share consumers:
287
+
288
+
* Each thread polls and processes records independently
289
+
* Acknowledgment constraints apply per-thread (one thread's unacknowledged records don't block other threads)
290
+
* Concurrency setting must be greater than 0 and cannot be changed while the container is running
291
+
====
292
+
154
293
[[share-annotation-driven-listeners]]
155
294
== Annotation-Driven Listeners
156
295
@@ -520,8 +659,7 @@ Share consumers differ from regular consumers in several key ways:
520
659
=== Current Limitations
521
660
522
661
* **In preview**: This feature is in preview mode and may change in future versions
523
-
* **Single-Threaded**: Share consumer containers currently run in single-threaded mode
524
662
* **No Message Converters**: Message converters are not yet supported for share consumers
525
663
* **No Batch Listeners**: Batch processing is not supported with share consumers
526
-
* **Poll Constraints**: In explicit acknowledgment mode, unacknowledged records block subsequent polls
664
+
* **Poll Constraints**: In explicit acknowledgment mode, unacknowledged records block subsequent polls within each consumer thread
0 commit comments