-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
HBASE-27784: support quota user overrides #5424
Conversation
...-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaUserOverrideConfiguration.java
Outdated
Show resolved
Hide resolved
// defines the request attribute key which, when provided, will override the request's username | ||
// from the perspective of user quotas. This is also the default request attribute key | ||
public static final String QUOTA_USER_REQUEST_ATTRIBUTE_OVERRIDE_KEY = | ||
"hbase.quota.user.override.key"; |
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 main advantage of making this configurable is so that users can make use of existing attributes. For example we already submit an "upstream caller" identifier in our request attributes so that they will manifest in the slow query logs (introduced here). It would be nice to make use of that attribute here rather than requiring that we send superfluous bytes over the wire for each request
hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/QuotaCache.java
Outdated
Show resolved
Hide resolved
🎊 +1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
7c99721
to
ac13213
Compare
🎊 +1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
The test failures above look unrelated |
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.
Nice, straightforward addition. I'm curious about the config name, but otherwise looks good.
hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/QuotaCache.java
Show resolved
Hide resolved
hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/QuotaCache.java
Outdated
Show resolved
Hide resolved
hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaUserOverride.java
Outdated
Show resolved
Hide resolved
...-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaUserOverrideConfiguration.java
Outdated
Show resolved
Hide resolved
hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaUserOverride.java
Outdated
Show resolved
Hide resolved
assertEquals(10, doPuts(10, FAMILY, QUALIFIER, tableWithoutThrottle)); | ||
|
||
// Remove all the limits | ||
admin.setQuota(QuotaSettingsFactory.unthrottleUser(userOverrideWithQuota)); |
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.
testing that removing the limits dynamically is honored -- nice.
Yeah I've noticed that |
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
Optional<RpcCall> rpcCall = RpcServer.getCurrentCall(); | ||
if ( | ||
rpcCall.isPresent() | ||
&& rpcCall.get().getRequestAttributes().containsKey(userOverrideRequestAttributeKey) |
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 might recommend just looping the raw rpcCall.get().getHeader().getAttributes()
here. For a small N (as i expect attributes to be), it is typically faster to iterate the list than to lookup in a map. This is especially true if we have to actually build the map as well (as we are likely to here). So in a vacuum, this call loops all the attributes and populates a map (which involves hashcode and equals for each, not to mention converting from ByteString to byte[] and string). Then we do a lookup, which involves another hashcode and equals. On the other hand, a loop can exit out early if a match is found and only requires equals.
So if we planned to do many operations on the map, it might start to pay off to do those conversions. But if we are just looking for a single key in an empty or very small list, it'd be cheaper to skip all of that.
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 that makes sense, seems like a reasonable optimization. should we bake that into an RpcCall#getRequestAttribute(String key)
method to help this pattern be standard or is that overkill?
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.
Yea, let's do that. We can have it pull from the map if it's non-null, and otherwise loop. Just add javadoc describing the difference between that and getRequestAttributes() and when to use each.
💔 -1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
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.
LGTM -- Any other thoughts on your side @ndimiduk?
🎊 +1 overall
This message was automatically generated. |
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
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
Signed-off-by: Nick Dimiduk <ndimiduk@apache.org> Signed-off-by: Bryan Beaudreault <bbeaudreault@apache.org>
Signed-off-by: Nick Dimiduk <ndimiduk@apache.org> Signed-off-by: Bryan Beaudreault <bbeaudreault@apache.org>
Signed-off-by: Nick Dimiduk <ndimiduk@apache.org> Signed-off-by: Bryan Beaudreault <bbeaudreault@apache.org>
Description
At my day job we struggle to use quotas effectively for our most important HBase users. This is because our most important users are often proxy APIs which are queried by countless "upstream" microservices. It isn't feasible for these proxy APIs to spin up new connections for each request, so it isn't feasible to have distinct UserGroupInformation at request granularity. This leaves us unable to throttle these upstream microservices in isolation.
In #5326 we added support for "request attributes" — these are like operation attributes, except they exist 1:1 with RpcCalls rather than 1:1 with operations. In this PR we build on the request attribute framework and introduce the ability to specify a "quota user override" so that one can apply separate throttles to many requests sent by a single shared Connection.
Usage
For example, one may add the following property to their HBase configuration:
One could then create a Table with a quota user override via the TableBuilder:
cc @bbeaudreault @hgromer @eab148 @bozzkar