-
Notifications
You must be signed in to change notification settings - Fork 713
[DNM][CORE-15273] kafka/server: client quota perf optmization #29506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DNM][CORE-15273] kafka/server: client quota perf optmization #29506
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements performance optimizations for client quota operations by adding a rule counter mechanism and refactoring the quota lookup logic.
Changes:
- Moved
client_quota_ruleenum to a shared location (cluster::client_quota::rule) to enable reuse across components - Added rule counters to the quota store to track active quota rules and skip checking inactive ones
- Simplified benchmark tests by removing unused quota configuration parameters
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/v/kafka/server/tests/quota_manager_bench.cc | Removed unused fetch_tp field and associated benchmark test cases |
| src/v/kafka/server/quota_manager.cc | Updated references to use cluster::client_quota::all_client_quota_rules |
| src/v/kafka/server/client_quota_translator.h | Replaced local client_quota_rule definition with alias to cluster::client_quota::rule |
| src/v/kafka/server/client_quota_translator.cc | Refactored quota lookup to use rule counters for optimization and added helper functions |
| src/v/cluster/client_quota_types.h | New file defining shared rule enum and supporting constants |
| src/v/cluster/client_quota_types.cc | New file implementing stream operator for rule enum |
| src/v/cluster/client_quota_store.h | Added rule counters array and prefix group filter overloads |
| src/v/cluster/client_quota_store.cc | Implemented rule counter updates on quota set/remove/clear operations |
| src/v/cluster/BUILD | Added new client_quota_types source and header files |
| return os << "kafka_user_client_prefix"; | ||
| case rule::kafka_user_client_id: | ||
| return os << "kafka_user_client_id"; | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switch statement is missing a default case or return statement at the end, which can lead to undefined behavior if an invalid enum value is passed.
| } | |
| } | |
| return os << "unknown"; |
| rule get_rule(const entity_key& key) { | ||
| const bool has_user = has_part<entity_key::part::user_match>(key); | ||
| const bool has_user_default | ||
| = has_part<entity_key::part::user_default_match>(key); | ||
| const bool has_client_id = has_part<entity_key::part::client_id_match>(key); | ||
| const bool has_client_prefix | ||
| = has_part<entity_key::part::client_id_prefix_match>(key); | ||
| const bool has_client_default | ||
| = has_part<entity_key::part::client_id_default_match>(key); | ||
|
|
||
| if (has_user) { | ||
| if (has_client_id) { | ||
| return rule::kafka_user_client_id; | ||
| } | ||
| if (has_client_prefix) { | ||
| return rule::kafka_user_client_prefix; | ||
| } | ||
| if (has_client_default) { | ||
| return rule::kafka_user_client_default; | ||
| } | ||
| return rule::kafka_user; | ||
| } | ||
|
|
||
| if (has_user_default) { | ||
| if (has_client_id) { | ||
| return rule::kafka_user_default_client_id; | ||
| } | ||
| if (has_client_prefix) { | ||
| return rule::kafka_user_default_client_prefix; | ||
| } | ||
| if (has_client_default) { | ||
| return rule::kafka_user_default_client_default; | ||
| } | ||
| return rule::kafka_user_default; | ||
| } | ||
|
|
||
| if (has_client_id) { | ||
| return rule::kafka_client_id; | ||
| } | ||
| if (has_client_prefix) { | ||
| return rule::kafka_client_prefix; | ||
| } | ||
| if (has_client_default) { | ||
| return rule::kafka_client_default; | ||
| } | ||
|
|
||
| return rule::not_applicable; | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic does not handle the case where both has_user and has_user_default are true, which could occur with malformed keys. Consider adding validation or asserting mutual exclusivity of these flags.
| case client_quota_rule::kafka_user_default_client_prefix: | ||
| case client_quota_rule::kafka_user_client_prefix: | ||
| vassert(false, "make_entity_key should not be called on these rules"); | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switch statement is missing a return or vassert at the end. If an unexpected enum value is passed, the function may return with undefined behavior.
| } | |
| } | |
| vassert( | |
| false, | |
| "Unknown client_quota_rule in make_entity_key: {}", | |
| static_cast<int>(r)); |
| case client_quota_rule::kafka_user_client_default: | ||
| case client_quota_rule::kafka_user_client_id: | ||
| vassert(false, "make_entity_key should not be called on these rules"); | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switch statement is missing a return or vassert at the end to handle potential undefined behavior if an unexpected enum value is passed.
| } | |
| } | |
| vassert(false, "Unexpected client_quota_rule in make_group_quotas: {}", | |
| r); |
| tracker_key make_tracker_key( | ||
| const std::string_view k1_name, const std::string_view k2_name) { | ||
| return tracker_key{ | ||
| std::in_place_type<std::pair<K1, K2>>, std::make_pair(k1_name, k2_name)}; | ||
| const client_quota_rule r, | ||
| std::string_view user, | ||
| // This is either the client name or the group name | ||
| std::string_view client_id) { | ||
| switch (r) { | ||
| case client_quota_rule::not_applicable: | ||
| return tracker_key{std::in_place_type<k_not_applicable>}; | ||
| case client_quota_rule::kafka_client_default: | ||
| return tracker_key{std::in_place_type<k_client_id>, client_id}; | ||
| case client_quota_rule::kafka_client_prefix: | ||
| return tracker_key{std::in_place_type<k_group_name>, client_id}; | ||
| case client_quota_rule::kafka_client_id: | ||
| return tracker_key{std::in_place_type<k_client_id>, client_id}; | ||
| case client_quota_rule::kafka_user_default: | ||
| return tracker_key{std::in_place_type<k_user>, user}; | ||
| case client_quota_rule::kafka_user_default_client_default: | ||
| return tracker_key{ | ||
| std::in_place_type<std::pair<k_user, k_client_id>>, | ||
| std::make_pair(user, client_id)}; | ||
| case client_quota_rule::kafka_user_default_client_prefix: | ||
| return tracker_key{ | ||
| std::in_place_type<std::pair<k_user, k_group_name>>, | ||
| std::make_pair(user, client_id)}; | ||
| case client_quota_rule::kafka_user_default_client_id: | ||
| return tracker_key{ | ||
| std::in_place_type<std::pair<k_user, k_client_id>>, | ||
| std::make_pair(user, client_id)}; | ||
| case client_quota_rule::kafka_user: | ||
| return tracker_key{std::in_place_type<k_user>, user}; | ||
| case client_quota_rule::kafka_user_client_default: | ||
| return tracker_key{ | ||
| std::in_place_type<std::pair<k_user, k_client_id>>, | ||
| std::make_pair(user, client_id)}; | ||
| case client_quota_rule::kafka_user_client_prefix: | ||
| return tracker_key{ | ||
| std::in_place_type<std::pair<k_user, k_group_name>>, | ||
| std::make_pair(user, client_id)}; | ||
| case client_quota_rule::kafka_user_client_id: | ||
| return tracker_key{ | ||
| std::in_place_type<std::pair<k_user, k_client_id>>, | ||
| std::make_pair(user, client_id)}; | ||
| } | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switch statement is missing a return or default case at the end. If an unexpected enum value is passed, the function may return with undefined behavior.
|
Results of
|
Retry command for Build#80033please wait until all jobs are finished before running the slash command |
2e1403b to
1dc3751
Compare
|
Given the complexity of the optimization, it was decided to take the perf-hit. |
Fixes: CORE-15273
introduces a tally for each rule present in client quota store. Only rules that have active entries are considered when trying to resolve an entity key.
Backports Required
Release Notes