Scenario 11.0.6 · Implicit vs explicit acknowledgement mode
Kafka share.acknowledgement.mode: implicit vs explicit
IMPLICIT auto-accepts on the next poll; EXPLICIT keeps records in-flight until the member acks - or the lock expires and redelivers (KIP-932).
Run this scenario in the playgroundCluster ready · idle. t+0.000s
One partition, three records pending, and TWO single-member share groups that differ ONLY in ackMode: 'imp' (implicit) vs 'exp' (explicit). Both have a 1000ms lock. Press ▶.
Open at this step: step 1, Cluster ready · idleBoth groups acquire. t+0.700s
First poll (600ms): each group's member acquires all three records (deliveryCount 1, locked until 1600ms). Acquiring alone does NOT make a record terminal, so SPSO stays at 0 and both groups read lag 3.
Open at this step: step 2, Both groups acquireImplicit auto-acked; explicit still in-flight. t+1.300s
The contrast. IMPLICIT auto-accepted all three on its next poll (1200ms) with no application ack → acked, lag 0. EXPLICIT only acked offsets 0 and 1 (the ones the app called share_ack on); offset 2 is still acquired, so its SPSO is stuck at 2 (lag 1).
Open at this step: step 3, Implicit auto-acked; explicit still in-flightExplicit un-acked lock expires. t+1.700s
Offset 2 was never acked, so at 1600ms its acquisition lock EXPIRED - the record is released back to 'available' (still deliveryCount 1). Implicit never reached this path; explicit's lock-expiry is the safety net that stops a crashed handler from silently dropping a record.
Open at this step: step 4, Explicit un-acked lock expiresExplicit record redelivered. t+1.900s
The next poll (1800ms) re-acquires offset 2 - deliveryCount climbs to 2: a REDELIVERY. Explicit ack buys at-least-once control at the cost of a possible duplicate; the implicit group acked-and-forgot and never duplicated anything.
Open at this step: step 5, Explicit record redeliveredWhat you start with
share.acknowledgement.mode controls how records are confirmed. This A/B runs two single-member groups over the same three records: the implicit group auto-accepts each record on its NEXT poll with no application ack, while the explicit group must call share_ack - and the one offset it deliberately leaves un-acked has its lock expire (lockMs 1000) and is redelivered.
Step by step
- Cluster ready · idle t+0.000s One partition, three records pending, and TWO single-member share groups that differ ONLY in ackMode: 'imp' (implicit) vs 'exp' (explicit). Both have a 1000ms lock. Press ▶. Open at this step: step 1, Cluster ready · idle
- Both groups acquire t+0.700s First poll (600ms): each group's member acquires all three records (deliveryCount 1, locked until 1600ms). Acquiring alone does NOT make a record terminal, so SPSO stays at 0 and both groups read lag 3. Open at this step: step 2, Both groups acquire
- Implicit auto-acked; explicit still in-flight t+1.300s The contrast. IMPLICIT auto-accepted all three on its next poll (1200ms) with no application ack → acked, lag 0. EXPLICIT only acked offsets 0 and 1 (the ones the app called share_ack on); offset 2 is still acquired, so its SPSO is stuck at 2 (lag 1). Open at this step: step 3, Implicit auto-acked; explicit still in-flight
- Explicit un-acked lock expires t+1.700s Offset 2 was never acked, so at 1600ms its acquisition lock EXPIRED - the record is released back to 'available' (still deliveryCount 1). Implicit never reached this path; explicit's lock-expiry is the safety net that stops a crashed handler from silently dropping a record. Open at this step: step 4, Explicit un-acked lock expires
- Explicit record redelivered t+1.900s The next poll (1800ms) re-acquires offset 2 - deliveryCount climbs to 2: a REDELIVERY. Explicit ack buys at-least-once control at the cost of a possible duplicate; the implicit group acked-and-forgot and never duplicated anything. Open at this step: step 5, Explicit record redelivered
The takeaway
Implicit mode is simplest for fire-and-forget processing; explicit mode trades a manual ack for precise at-least-once control, with lock expiry redelivering anything you forget to confirm.
Configs in this scenario
-
share.How a share-group consumer acknowledges the records it acquires: implicit auto-accepts every acquired record on the next poll (the application just keeps polling), while explicit requires the application to call acknowledge(record, type) per record to ACCEPT / RELEASE / REJECT / RENEW it - under explicit mode an un-acknowledged record stays in-flight until its acquisition lock expires and is then redelivered.acknowledgement. mode
Embed this scenario
Paste this into a blog post, a course page or your team's docs. The scenario plays inside your page, and the link under it points readers to this walkthrough.
<iframe src="https://monedula.dev/kafka-simulator/embed/?scenario=11.0.6" title="Kafka Simulator: Implicit vs explicit acknowledgement mode" width="100%" height="520" style="border:1px solid #d0d0d0;border-radius:8px" loading="lazy"></iframe>
<p><a href="https://monedula.dev/kafka-simulator/scenarios/implicit-vs-explicit-ack/">Kafka share.acknowledgement.mode: implicit vs explicit</a></p> Further reading
KIP-932 on the Apache Kafka wiki
More in Share groups
- Kafka share groups: queue semantics with KIP-932
- More Kafka consumers than partitions with share groups
- Kafka share group acquisition lock timeout and redelivery
- Kafka share consumer acknowledge: accept, release, reject
- Kafka share group poison pill: delivery limit and archiving
- Kafka share.acquire.mode: batch_optimized vs record_limit
- Renew a Kafka share group acquisition lock (KIP-1222)
- Kafka share group lag: SPSO, SPEO and the acked prefix