Status

Current state: Under discussion

Discussion thread: here

JIRA:

Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast).

Motivation

KIP-932 introduced queueing semantics in Kafka with new group and consumer types: share groups and share consumers. Multiple share consumers in a share group can subscribe to user topics and consume data cooperatively without partition limits.

A share consumer can operate in implicit or explicit mode. In implicit mode, the acknowledgement type is fixed to ACCEPT. In explicit mode, each record must be acknowledged explicitly. The acknowledgement types are:

When a share consumer polls a batch of records, the server attaches an acquisition lock timeout task to the batch. If the batch is not acknowledged before the acquisition lock expires, it transitions to available state and becomes eligible for re-delivery (unless delivery count limit is exceeded). The broker cancels and clears the acquisition lock timeout task on ACCEPT or REJECT. On RELEASE state is moved to available and acquisition task is restarted on next delivery attempt.

If a user application using a share consumer in explicit mode processes a record for a long time, it cannot use any acknowledgement type to affect the server acquisition lock timeout without changing the record state. If processing exceeds the timeout duration, the acquisition lock expires and the record is re-delivered, which may be undesirable.

This KIP proposes a new acknowledgement type, RENEW, for explicit mode. It lets a share consumer request the broker to renew the acquisition lock timeout, thereby extending the current delivery attempt without changing the server's record state.

Public Interfaces

Proposed Changes

KIP-932 added two new RPCs for record fetching and acknowledging: ShareFetch and ShareAcknowledge. From the share consumer, these RPCs are called when an application invokes poll(Duration), acknowledge(ConsumerRecord, AcknowledgementType), or commitSync(Duration)/commitAsync().

In implicit mode, an application calls poll() on the share consumer and receives a batch of records. It can acknowledge these records on a subsequent call to poll() (piggybacking on ShareFetch). Calling commitSync()/commitAsync() sends a ShareAcknowledge but only the ACCEPT acknowledgement type is used. Calling acknowledge(ConsumerRecord, AcknowledgementType) is illegal in this mode. This KIP does not target implicit mode.

In explicit mode, polling works the same, but the application must acknowledge each record explicitly using one of the AcknowledgementType values. If record processing might take time, the application should use the new acknowledgement type RENEW as an argument to acknowledge(ConsumerRecord, AcknowledgementType) for that record. It can then call either commitSync()/commitAsync() or poll() to send the acknowledgement to the server. Furthermore, the application could also leverage the new ShareConsumer.acquisitionLockTimeoutMs() method to decide on the timeframe in which to make the RENEW call.

On the broker side, receiving a RENEW acknowledgement for a specific batch or offset will cancel the existing acquisition lock timeout task and start a new one with the same timeout value as group.share.record.lock.duration.ms. There is one caveat here. If the application causes a ShareFetch RPC to be sent (poll() call) on which RENEW acknowledgements are piggybacked, it could happen that the renewed acquisition lock again times out before the poll() completes. To get around this, we will not return any data from the broker side on ShareFetch requests containing RENEW acknowledgements. That way we are guaranteed that the poll()  completes timely.

We assume the application uses appropriate concurrency constructs to process records in separate threads.

Compatibility, Deprecation, and Migration Plan

Test Plan