Skip to content
Knowledge Hub

Kafka Share Groups (Kafka Queues): many workers processing one partition Intermediate

Estimated reading time: 7 min read

Topic image-jobs has one partition. You grow the group from 1 to 8 consumers but throughput does not change: in a regular consumer group, a partition is assigned to only one consumer, and the other seven sit idle. Adding partitions changes key distribution and ordering, and cannot be undone.

Share Groups (also called Kafka Queues, KIP-932) let many consumers take different records from the same partition. Each record is held by a time-limited lock and then acked individually. Producers still write to a regular Kafka topic.

Version Status Source
4.0 Early access (test clusters only, cannot upgrade to 4.1) 4.0 release announcement
4.1 Preview, enabled with kafka-features.sh (share.version=1) Upgrade notes
4.2 Production-ready Upgrade notes and release announcement

Operational notes for 4.2: clusters with fewer than 3 brokers must set share.coordinator.state.topic.replication.factor and share.coordinator.state.topic.min.isr to 1 before use; the docs state that 4.2.1 fixes a serious deadlock in the share group path, so use the latest patch.

This repo uses the cp-kafka:7.6.0 broker (Kafka 3.6, ZooKeeper) and KafkaJS 2.2 for older demos, so it cannot run Share Groups; KafkaJS has no Share Consumer API. The example below is an in-memory model.

Consumer group Share group RabbitMQ quorum queue
Unit of work distribution Partition Record Message
Useful workers At most the partition count Not limited by partitions Many consumers on one queue
Processing order By offset within a partition Not guaranteed Not guaranteed with multiple consumers
Ack Contiguous offset commit Per record (ACCEPT/RELEASE/REJECT/RENEW) Per message (ack/nack)
Redelivery limit None group.share.delivery.count.limit, default 5 delivery-limit, default 20 since 4.0
Lock expiry None share.record.lock.duration.ms, default 30 seconds Per consumer ack timeout
Replay Seek to offset Not a goal No (regular queues)
Multiple groups reading the same data Yes Yes (topic retention still applies) Needs fan-out through an exchange
Config Default Notes
group.share.record.lock.duration.ms (broker) / share.record.lock.duration.ms (group) 30000 Minimum 1000 in the group config
group.share.delivery.count.limit (broker) 5 Beyond this many deliveries a record is not delivered again
group.share.partition.max.record.locks (broker) 2000 Cap on locked records per partition
share.auto.offset.reset (group) latest A new share partition starts at the end of the log, not the beginning
share.isolation.level (group) read_uncommitted read_committed to skip uncommitted transactions
share.session.timeout.ms 45000 Detects dead clients
share.heartbeat.interval.ms 5000

Watch out for share.auto.offset.reset=latest: records produced before the first share group subscribes will not be delivered; to process an existing backlog, set earliest.

Two workers take different records from the same partition
Two workers take different records from the same partitionStep 1/4: A acquires offset 7. The record is temporarily locked for A and has not been successfully acked yet.PartitionWorker AWorker Boffset 7
Partition → Worker Aoffset 7
Step 1/4

A acquires offset 7. The record is temporarily locked for A and has not been successfully acked yet.

Kafka picks available records and acquires them for a consumer with a time-limited lock. While the lock is valid, the record is not delivered to another consumer; the next record of the same partition can be taken by a different worker.

With explicit acknowledgement (Java client):

Outcome AcknowledgeType Meaning
Success ACCEPT Marks it as processed
Transient error RELEASE Releases it for redelivery
Cannot be processed REJECT Not redelivered within the group
Long-running work RENEW Extends the lock

acknowledge() only records the intent on the client; acks are sent with the next poll or with commitSync()/commitAsync().

The default implicit mode treats records from the previous poll as successful when you poll again: convenient, but dangerous if the batch has a failing record. Use explicit mode for jobs that need error classification.

  1. Out-of-order completion. A takes offset 7, B takes offset 8 and finishes first. If 8 depends on 7, the result is wrong. Share groups promise no completion order.
  2. The lock expires while the worker is still running. A takes longer than 30 seconds, record 7 is delivered to B, and A still calls the external API: a duplicate side effect. A broker lock does not replace idempotency; use RENEW for long work.
  3. Permanent errors. REJECT or running out of deliveries only stops redelivery within the share group; it does not create a dead-letter topic. You must design the error store, alerts and replay yourself.
Situation Choose
Already on Kafka, independent jobs, need more workers than partitions, the same data is also read by analytics Share group (Kafka 4.2+)
Need pattern routing, priorities, rich TTL/DLX RabbitMQ (queue types)
Per-key ordering matters Consumer group, not a share group
Not yet running Kafka 4.2 Keep the consumer group with enough partitions, or use RabbitMQ
  • Use: independent jobs (thumbnails, sending email, calling APIs), “queue on Kafka” workloads.
  • Do not use: per-entity state machines, ledgers that need ordering, anywhere offset order is an invariant.
  • Do not use if you cannot yet upgrade the cluster to 4.2 and clients to the Share Consumer API.

An in-memory model (not output from real Kafka): A acquires 7, B acquires 8 and accepts, the lock on 7 expires and B receives 7 on the second delivery; the last line is completion order: 8, 7.

The lock in the demo is 30 ms to run fast; the real default is 30 seconds.

Terminal window
npx --prefix examples ts-node examples/src/kafka-share-groups/share-group-model.ts

To verify for real: a Kafka 4.2+ cluster and the Java KafkaShareConsumer, a one-partition topic, two consumers with the same group.id and share.acknowledgement.mode=explicit; stop one worker after acquire and before ack to observe redelivery.

When share groups fit

  • Many workers on one partition, not limited by the partition count.
  • Record-level ack and retry, per-job error classification.
  • Still a Kafka topic: other groups read independently.

Trade-offs

  • No completion order guarantee.
  • Expired locks, uncommitted acks and retries still cause duplicate processing.
  • Needs 4.2+ brokers and clients; extra operational work for delivery attempts, errors, retention.
  1. Use only for independent jobs; confirm there is no ordering invariant.
  2. Every job has a stable jobId and writes results idempotently.
  3. Use explicit acknowledgement; ACCEPT only after the result is durable.
  4. Set the lock duration above p99 processing time, use RENEW for long work.
  5. Design your own error store for REJECT and jobs out of deliveries (default 5).
  6. Set share.auto.offset.reset deliberately (earliest if you need to process a backlog).
  7. Track record age against the topic retention.

Self-check: (1) One partition and eight workers: how many can a consumer group use, and a share group? (2) Can offset 8 complete before 7? (3) Why can worker A, still running after its lock expired, cause a duplicate side effect?