Skip to content

KAFKA-20650: Share ClientQuotaCallback across broker and controller in combined mode#22792

Open
vismaytiwari wants to merge 2 commits into
apache:trunkfrom
vismaytiwari:KAFKA-20650-share-client-quota-callback
Open

KAFKA-20650: Share ClientQuotaCallback across broker and controller in combined mode#22792
vismaytiwari wants to merge 2 commits into
apache:trunkfrom
vismaytiwari:KAFKA-20650-share-client-quota-callback

Conversation

@vismaytiwari

Copy link
Copy Markdown

JIRA: https://issues.apache.org/jira/browse/KAFKA-20650

Problem

In combined (KRaft) mode, BrokerServer and ControllerServer each call QuotaFactory.instantiate(), which creates a separate ClientQuotaCallback via reflection per role. A custom callback is therefore instantiated twice with divergent state in one JVM — a regression from the pre-KRaft single-instance behavior.

Approach

Create the callback once in SharedServer (which the broker and controller already share for metrics, raftManager, etc.) and pass it into a new QuotaFactory.instantiate(...) overload that accepts a pre-built Optional<Plugin<ClientQuotaCallback>>, so both roles use the same instance. Separate-mode broker-only / controller-only behavior is unchanged (one role per SharedServer).

Open questions for reviewers (this is why I'm raising it as a discussion)

  1. Close ownership. The shared plugin is currently closed by each role's QuotaManagers.shutdown(), so in combined mode it is closed twice (benign via Utils.closeQuietly, but not ideal). I can instead track ownership so only SharedServer closes it, or have SharedServer own the close and QuotaManagers skip it — happy to implement whichever you prefer. I kept this PR minimal to align on the approach first rather than churn the QuotaManagers record + its test call sites.
  2. Config / role tag. The shared callback is built from sharedServerConfig with the broker role tag. In combined mode the broker/controller configs share the same props, but let me know if you'd prefer a different config or a combined role tag.

Testing / honesty

I couldn't run a local build for this (no JDK available in my environment), so I've relied on careful manual review and am leaning on CI here — apologies if something needs a fixup; I'll iterate quickly. Guidance on the two questions above would let me finish it cleanly.

AI disclosure: drafted with Claude (Claude Code) and reviewed; the commit carries the Co-Authored-By trailer per the contributing guide.

vismaytiwari and others added 2 commits July 9, 2026 12:12
The deserialize(String, Headers, ByteBuffer) Javadoc stated only what
callers and implementations cannot assume about the buffer (position,
limit, capacity), leaving the readable region and side-effect
expectations unspecified. This clarifies that the serialized bytes are
the buffer's remaining() bytes and that implementations should not
modify the buffer's position/limit/mark, since the caller may read the
buffer again afterward (for example, to determine the serialized value
size).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n combined mode

In combined (KRaft) mode, BrokerServer and ControllerServer each called
QuotaFactory.instantiate(), which created a separate ClientQuotaCallback
instance via reflection for each role. A custom callback was therefore
instantiated twice with divergent state in a single JVM - a regression
from the pre-KRaft single-instance behavior.

Create the callback once in SharedServer (already shared by the broker and
controller roles) and pass it to a new QuotaFactory.instantiate() overload
so both roles use the same instance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added triage PRs from the community core Kafka Broker clients small Small PRs labels Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clients core Kafka Broker small Small PRs triage PRs from the community

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant