-
Notifications
You must be signed in to change notification settings - Fork 31
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
Add Kafka quota enforcer #53
Add Kafka quota enforcer #53
Conversation
7bb1b1b
to
8ffa4e5
Compare
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.
Looking great, made some minor comments.
Time.SYSTEM, | ||
"kafka.server", // default used in the client | ||
"SessionExpireListener" // default used in the client | ||
); |
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.
A general comment, its a good practice to declare the variable as final as much as possible in many cases it doesn't have an obvious benefit, but in multi-threaded code, it can protect you from bugs
|
||
@Override | ||
protected Enforcer<ConfiguredQuota> initEnforcer() { | ||
Map<String, Object> zookeeperConfig = zookeeperConfig(); |
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.
nit: rename this variable, it conflicts with the method name
this.adminClient = adminClient; | ||
} | ||
|
||
enum Type { |
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.
can you add some docs here explaining what each of these mean?
8ffa4e5
to
c1a7f20
Compare
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.
+1. Get Jesse's 👀 too.
c1a7f20
to
9831504
Compare
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.
Some nits and testing improvements, but overall looks great!
bazel build //kafka_quota_enforcer/src/main/java/com/tesla/data/quota/enforcer:Main_deploy.jar | ||
``` | ||
|
||
### Verify |
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.
Its not clear what to expect from these commands
kafka_quota_enforcer/README.md
Outdated
|
||
* A quota applies to a cluster if that cluster is present under quota's `clusters` | ||
attribute. If no changes to base config are desired, specify empty dict `{}` | ||
* Any quota value can be overridden. Quota 'principal' or 'client' properties should not be overridden. |
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.
i would expect the enforcer to fail in that case (and thus the comment would read "If the 'principal' or 'client' properties are overridden, enforcing will fail")... but i assume this is not possible? In which case how about "'principal' or 'client' are not recommended to be overridden.
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.
yeah, don't think it's currently supported to restrict specific fields from being overridden. Will add in "not recommended"
kafka_quota_enforcer/README.md
Outdated
* Map (dictionary) properties are merged in a way that preserves base settings | ||
|
||
|
||
Note: `quotasFile` is supported for multi-cluster configuration too. |
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.
Note: quotasFile
supports multi-cluster configuration as well.
kafka_quota_enforcer/README.md
Outdated
You can read more about it here: https://kafka.apache.org/documentation/#design_quotas | ||
|
||
To specify a default quota, simply use `<default>` as the value in the quota's `principal` or `client` config fields. | ||
For example, to set a default quota for clients groups that have unique principals, here's a sample `quotasFile.yaml`: |
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.
For example, to set the default quota for each unique principal - regardless of the client - you could use:
public void setup() { | ||
quotaService = mock(QuotaService.class); | ||
enforcer = new QuotaEnforcer(emptyList(), quotaService, true, true); | ||
quotas = Arrays.asList( |
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.
why not just make static, final and set above?
configuration file is expected | ||
``` | ||
|
||
## Configuration |
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.
There is no discussion of precedence of quotas for client/principal combinations, or at least a pointer to the kafka docs describing the hierarchy. Can lead to unexpected outcomes and/or confusion for users
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.
thanks, forgot about that
kafka_quota_enforcer/README.md
Outdated
* cluster default | ||
* default | ||
|
||
# Setting 'default' quotas |
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.
How about calling a "low water mark"... really anything besides default
:)
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.
changed to "entity-default" - it seems that referencing 'default' in the title is important as that's what users will be looking for in the docs, and "entity-default" would help to relate that back to the kafka-configs command usage
Integer requestPercentage = quota.get(REQUEST_PERCENTAGE) != null ? | ||
Integer.parseInt(quota.getProperty(REQUEST_PERCENTAGE)) : null; | ||
|
||
switch (quotaType) { |
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.
isn't this an entityType?
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.
No change?
this.adminClient = adminClient; | ||
} | ||
|
||
enum Type { |
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.
Doesn't EntityType
more closely describe what 'type' means here?
} | ||
|
||
@Override | ||
public boolean equals(Object o) { |
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.
minor style nit: generally equals/hashcode/toString are at the bottom of the class
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.
generally hashcode goes next to equals - they should be logically the same
9831504
to
152fa0f
Compare
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.
Some more nits, but lgtm otherwise
} | ||
|
||
@Override | ||
public boolean equals(Object o) { |
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.
generally hashcode goes next to equals - they should be logically the same
|
||
enum Type { | ||
// quota applied solely on a per principal/user basis, ex: principal=user1 | ||
USER, |
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.
Everything in ZK and Kafka says principal - it is strictly different than a 'user' https://stackoverflow.com/questions/4989063/what-is-the-meaning-and-difference-between-subject-user-and-principal
Integer requestPercentage = quota.get(REQUEST_PERCENTAGE) != null ? | ||
Integer.parseInt(quota.getProperty(REQUEST_PERCENTAGE)) : null; | ||
|
||
switch (quotaType) { |
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.
No change?
case CLIENT: | ||
return new ConfiguredQuota(null, quotaEntry.getKey(), producerByteRate, consumerByteRate, requestPercentage); | ||
case COMBINATION: | ||
// when both user + client are configured, the full name looks like {configuredUser}/clients/{configuredClient} |
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.
You can name the groups as well and then reference them by name, for instance "(<principal>.*)/clients/(<client>.*)"
then you can do new ConfiguredQuota(matcher.group("principal"), matcher.group("client")
which is very explicit
public void testCreate() { | ||
QuotaEnforcer enforcer = new QuotaEnforcer(emptyList(), quotaService, true, false); | ||
enforcer.create(quotas); | ||
verify(quotaService, times(1)).create(quotas); |
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.
nit: times(1) is the default with verify(), you can just drop the times parameter
… quotas to restrict monopolization of Kafka broker resources caused by bad acting clients.
152fa0f
to
696bfb5
Compare
Enables programmatic configuration of Kafka quotas to restrict monopolization of Kafka broker resources caused by bad acting clients.
https://kafka.apache.org/documentation/#design_quotas