Skip to content
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

Node-wide throughput exemptions for clients #10755

Merged
merged 9 commits into from
Jun 3, 2023

Conversation

dlex
Copy link
Contributor

@dlex dlex commented May 15, 2023

This PR introduces a feature to make client_ids specified by a value, regex, or by a special selector for missing client_ids exempt from throughput control. Connections presenting a matching client_id value will not have the size of their requests accounted for throughput control, not they will be throttled.

The new configuration is forward looking to support the fully functional throughput control groups, this is why it may look too bulky for this specific PR.

Fixes #10575

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v23.1.x
  • v22.3.x
  • v22.2.x

Release Notes

Improvements

  • A client_id, or a group of client_ids specified with a regex, can now be excluded from node wide throughput control. The new cluster property kafka_throughput_control can be used to define throughput control groups for which Kafka traffic will not be limited by the values specified by kafka_throughput_limit_node_*_bps.

@dlex dlex requested review from dotnwat and graphcareful May 15, 2023 06:39
@dlex dlex removed the request for review from graphcareful May 15, 2023 06:40
@dlex dlex marked this pull request as ready for review May 15, 2023 06:41
@dlex dlex added this to the v23.2.1 milestone May 15, 2023
@dlex dlex marked this pull request as draft May 15, 2023 17:39
@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from 6d19d35 to 99cfeb4 Compare May 15, 2023 18:04
@dlex dlex marked this pull request as ready for review May 15, 2023 18:18
@dlex dlex requested a review from BenPope May 15, 2023 18:20
@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from 99cfeb4 to c2174e0 Compare May 16, 2023 00:55
@dlex
Copy link
Contributor Author

dlex commented May 16, 2023

Force push: fixed a followup from #10285, avoid possible segfault when "kafka_throughput_controlled_api_keys" changes on the fly.

@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from c2174e0 to bfe47f0 Compare May 18, 2023 22:51
@dlex
Copy link
Contributor Author

dlex commented May 18, 2023

Force push:

  • example added to the configuration so that test_valid_settings does not fail on it
  • use the existing property_type_name instead of the new memeber name to define configuration type
  • validation function now returns std::nullopt for success as expected by property
  • error message extended in test_valid_settings

@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from bfe47f0 to 64fb201 Compare May 19, 2023 00:51
@dlex
Copy link
Contributor Author

dlex commented May 19, 2023

Force push: unit test fixed

@dlex
Copy link
Contributor Author

dlex commented May 20, 2023

/ci-repeat 3

Copy link
Member

@dotnwat dotnwat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great. just a few suggestions about simplifying some stuff like the std::variant usage but those aren't blockers or anything.

Comment on lines 74 to 75
struct unspecified_tag {};
std::variant<unspecified_tag, copyable_RE2> v;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this what std::monostate is for, or would this be better represented as optional<RE2>?

Copy link
Contributor Author

@dlex dlex May 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this what std::monostate is for

not exactly, monostate is more for "uninitalized" semantics while this one is specifically for "unspecified", that's why I used a separate tag. In theory, there may be more that just these two.

or would this be better represented as optional

it may, but the value of this type is wrapped into optional itself, so this variant is in part to avoid optional<optional<RE2>>

Copy link
Member

@dotnwat dotnwat May 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh yeh, optional<optional<re2>> is sus, but generally i think the outcome is better when stuff is represented as directly as possible, even if it means weird stuff like nested optionals. in actual usages you can unwrap each layer of the optional and then add a comment or something about what is going on.

Comment on lines 97 to 140
return re2::RE2::FullMatch(
re2::StringPiece(client_id.c_str(), client_id.length()), *client_id_re);
return std::visit(
[client_id](auto&& v) -> bool {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<
T,
client_id_matcher_type::unspecified_tag>) {
// only missing client_id matches the unspecified tag
return !client_id;
} else if constexpr (std::is_same_v<T, copyable_RE2>) {
// missing client_id never matches a re
return client_id
&& re2::RE2::FullMatch(re2::StringPiece(*client_id), v);
} else {
static_assert(
always_false_v<T>, "non-exhaustive client_id_re_type visitor");
}
},
client_id_matcher->v);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this PR introduces throughput_control_group.cc why have this other commit that rewrites a bunch of it? seems like this should be squashed with the second commit to avoid extra reviewing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to split the large file into smaller parts to make reviewing easier :) If that's the other way around actually, I will squash

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeh i mean i think it's fine the way it is. i only mentioned it because it seemed like enough code was changing that it wasn't necessarily making review easier. but it isn't a problem either way.

Comment on lines 123 to 139
return std::visit(
[client_id](auto&& v) -> bool {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<
T,
client_id_matcher_type::unspecified_tag>) {
// only missing client_id matches the unspecified tag
return !client_id;
} else if constexpr (std::is_same_v<T, copyable_RE2>) {
// missing client_id never matches a re
return client_id
&& re2::RE2::FullMatch(re2::StringPiece(*client_id), v);
} else {
static_assert(
always_false_v<T>, "non-exhaustive client_id_re_type visitor");
}
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be if std::holds_alternative instead of using visit with constexpr etc... but maybe using optional woudl be even simpler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've compared the above code with holds_alternative approach:

    if (std::holds_alternative<client_id_matcher_type::unspecified_tag>(
          client_id_matcher->v)) {
        // only missing client_id matches the unspecified tag
        return !client_id;
    }
    if (auto* const v = std::get_if<copyable_RE2>(&client_id_matcher->v); v) {
        // missing client_id never matches a re
        return client_id
               && re2::RE2::FullMatch(re2::StringPiece(*client_id), *v);
    }
    assert(false, "non-exhaustive client_id_re_type visitor");

So it's a comparable amount of code, a bit simpler, but it has an important drawback: a runtime fallback case. With visit, a missed case will cause compilation to fail, but with holds_alternative it will be a runtime assert/soft assert.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe using optional woudl be even simpler?

+1

src/v/config/throughput_control_group.cc Outdated Show resolved Hide resolved
src/v/kafka/server/snc_quota_manager.cc Show resolved Hide resolved
src/v/kafka/server/snc_quota_manager.cc Outdated Show resolved Hide resolved
client_id);
if (tcgroup_it == _kafka_throughput_control().cend()) {
ctx->_exempt = false;
vlog(klog.info, "qm - No throghput control group assigned");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these be at info level?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the normal course that would happen once per connection lifetime, so I think info is fine. Unless we have supported clients that open and drop kafka connections all the time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we log anything else at connection establishment at info level? i don't think we do...

Copy link
Contributor Author

@dlex dlex May 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we log at INFO at connection loss here, but that's an exceptional future handling, so that does not happen on graceful connection close. Ok I'll demote it to DEBUG to align with the rest of connection event

src/v/kafka/server/snc_quota_manager.h Show resolved Hide resolved
@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from 64fb201 to c975ac2 Compare May 23, 2023 06:26
@dlex
Copy link
Contributor Author

dlex commented May 23, 2023

Force push:

  • dropped variant in favour of optional
  • hid snc_quota_context
  • spelling

@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from c975ac2 to 1cd7048 Compare May 23, 2023 06:30
@dlex
Copy link
Contributor Author

dlex commented May 23, 2023

Force push: rebased upstream

@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from 1cd7048 to 9e375ba Compare May 23, 2023 18:15
@dlex
Copy link
Contributor Author

dlex commented May 23, 2023

Force push:

  • snc_quota_manager_context returned to the header

@dlex dlex requested a review from dotnwat May 23, 2023 19:45
@dlex dlex requested a review from dotnwat May 30, 2023 04:09
@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from 07786f1 to cdaf180 Compare May 30, 2023 21:43
@dlex
Copy link
Contributor Author

dlex commented May 30, 2023

Force push: a typo fixed in property description

dlex added 9 commits June 2, 2023 12:02
Followup to redpanda-data#10285. There the intake traffic point was left
unconditional of the api key, which caused anomalities in tput related
metrics.
throughput_control_group is a structural element for tput control groups
configuration. This commit adds its implementation sufficient to cover
tput exemptions by client_id matched with a regex.
always_false_v moved to utils/functional.h so that it can be reused
Client can omit client_id specification on its side. This is different
from empty client_id value, and for throughput_control_group it is
also different from omitting client_id (which means match anything
regardless of client_id). This commit introduces special selector tags for
client_id value in throughput_control_group. The syntax for selector
tags is "+name", this makes them distinct from any regex because regex
cannot start with a "+".

One selector name is introduced: "empty", it matches the omitted
client_id values and only them. To support that, throughput_control_group
does not store a regex directly anymore. Now it's a variant type
with one option for "empty" and another for the regex.
also a typo fixed in another description
connection_context now has all quota related stuff for the connection
stored in `_snc_quota_context`. This object is supposed to be created
once per connection lifetime by `snc_quota_manager`, but it will be
recreated each time a client_id changes on the connection.

When the quota context is created (lazily on the connection context),
the `kafka_throughput_control` rules are used to select the matching
throughput control group. If any group is matched, the context saves it
as a flag to exempt the connection from any snc_quota_manager control.
This will change into a full association with the control group.
Currently the exempt flag simply tells the quota manager to skip any
messages in that context.
Set some possible values for `kafka_throughput_control` in the
configurations test
@dlex dlex added the doc-needed label Jun 2, 2023
@dlex dlex force-pushed the 10575_tp-exemptions-for-clients branch from cdaf180 to 529cbf3 Compare June 2, 2023 16:26
@dlex
Copy link
Contributor Author

dlex commented Jun 2, 2023

Force push: rebased upstream

@dotnwat
Copy link
Member

dotnwat commented Jun 2, 2023

/ci-repeat 5

@dotnwat dotnwat merged commit 750bc90 into redpanda-data:dev Jun 3, 2023
@vbotbuildovich
Copy link
Collaborator

/backport v23.1.x

@vbotbuildovich
Copy link
Collaborator

Failed to run cherry-pick command. I executed the commands below:

git checkout -b backport-pr-10755-v23.1.x-706 remotes/upstream/v23.1.x
git cherry-pick -x 16a6cd0bd56bb16b3aa31a8b1577d97c10655a07 a1cc8f7b9d6d68e5a3efe1dc09b615cd61a82560 bd43f4727a9887bad52d8b56c77934e755c69a67 b1fa02e1b41bc76ba57409c6106b295a67fcbdcc 7af5c60a2836e65233c433c9e068faf7c1ea302c 2ded90fd6d1ed1b7f05a07c7353a190684386844 cd9b9518bdf395e695fbedba52bca74e6b523b0e edd1f11ebd671b97b4d36f3c35e159577433a3b5 529cbf39c14e32fca87352063e951f8f39cc30b5

Workflow run logs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cluster/Node Throughput Exemptions for Clients
4 participants