-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
local rate limit HTTP filter: add config interface #10820
local rate limit HTTP filter: add config interface #10820
Conversation
This is just the config API with an overview doc. Implementation will follow, once we have an agreement. See envoyproxy#10813. Signed-off-by: Raul Gutierrez Segales <rgs@pinterest.com>
// This field allows to send a HTTP response status code to the downstream client other | ||
// than 429 (TooManyRequests) when the request has been rate limited. | ||
type.v3.HttpStatus status = 1; |
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.
It's a possible scenario that the same rate limiter is applied to both grpc and http traffic (e.g. in case of transcoding or virtual_host-level rate limiter).
In this scenarios the status code options would conflict (as gRPC mandates the usage of 200 code).
Should grpc be introduced as first class citizen or are there other options?
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 mean, a same route that does both HTTP and gRPC?
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.
Yes, few examples:
- There is a single gRPC route
/service.Service/Method
but it hasenvoy.filters.http.grpc_json_transcoder
filter enabled. It allows the same route to serve both HTTP and gRPC traffic (all of it is converted to gRPC before going to upstream). Transcoding itself is potentially pricey (it requires buffering the whole request and is ≈reflection based), so one may want to put rate limiter before it. - Rate limiter is set for the whole
VirtualHost
, virtual host can serve traffic for different variations of traffic, e.g. it can have few gRPC and few HTTP upstreams.
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.
So we'd want to be able to configure an HTTP and a gRPC status code -- OK. Do we do this anywhere else in the API?
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.
Not anywhere today, though see #10841 where we are adding gRPC fault codes which is somewhat similar.
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.
Sorry, Whether the status
field could be set to universal? Then the rate-limit
filter module convert status-code depends on the requeste protocol. Here is a discuss #10813 .
@mattklein123 so my first question is, are we happy with using per filter configs to configure the local rate limiter or do we want to extend My take is that, for starters per filter configs gives us more freedom to experiment with this and once we are happy we can eventually merge this with core objects. Thoughts? |
Signed-off-by: Raul Gutierrez Segales <rgs@pinterest.com>
cc: @euroelessar on this too |
It feels to me that it should be a separate filter/extension, what are the reasons it needs to be a part of the |
Actually, no reasons now that I think about it... Given it won't be core functionality. Per filter configs tend to look less natural, but I think it's the right thing here. So I take the question back :-) |
|
||
api_proto_package( | ||
deps = [ | ||
"//envoy/api/v2/core:pkg", |
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.
v2 is now frozen, so please add directly to v3, thanks.
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.
ah ok.
// refills. | ||
type.v3.TokenBucket token_bucket = 2; | ||
|
||
// This uniquely identifies a specific local rate limit configuration (e.g.: when using per route |
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 thought the convention was that per-filter configs use the filter name as their key, so we don't technically need this.
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.
This is different -- lets say you are configuring local rate limiters on two different routes (/foo
and /bar
). This allows you to configure individual runtime keys for each route, so you can enable/enforce separately.
Is there a better way to distinguish the per-filter config of multiple routes/vhosts for things like runtime gatekeepers?
// have been rate limited. | ||
repeated config.core.v3.HeaderValueOption response_headers_to_add = 10 | ||
[(validate.rules).repeated = {max_items: 10}]; | ||
} |
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.
Did you consider making this a variation on the existing rate limit filter, with some additional config for local response? Asking since it might be the case that there is a bunch of shared config, e.g. request_type
, failure_mode_deny
.
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 did, but ended up concluding that there is much more in common with the network local rate limiter (than the existing HTTP global rate limiter).
@mattklein123 thoughts?
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 think originally had a similar inclination to @htuch about building this into the existing rate limit filter, but seeing this config it's simpler enough that I can buy having a separate filter for it. The only thing that would give me pause is whether someone is going to want to match on different types of things (descriptors) and whether we might be better served by constructing a descriptor as a key to a local token bucket? I'm not sure if this is worth it or not but just throwing it out there and I obviously didn't bother doing this for the network rate limit case (albeit a much simpler case). Thoughts?
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 for working on this. Flushing out a few comments/questions.
/wait
// rate limiters). It will be used to construct the | ||
// :ref:`runtime keys <config_http_filters_local_rate_limit_runtime>` that enable and enforce | ||
// the corresponding local rate limiter. | ||
string route_key = 3 [(validate.rules).string = {min_bytes: 1}]; |
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.
Should we just use RuntimeFractionalPercent or RuntimeFeatureFlag here or similar?
// This field allows to send a HTTP response status code to the downstream client other | ||
// than 429 (TooManyRequests) when the request has been rate limited. | ||
type.v3.HttpStatus status = 1; |
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.
Not anywhere today, though see #10841 where we are adding gRPC fault codes which is somewhat similar.
// have been rate limited. | ||
repeated config.core.v3.HeaderValueOption response_headers_to_add = 10 | ||
[(validate.rules).repeated = {max_items: 10}]; | ||
} |
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 think originally had a similar inclination to @htuch about building this into the existing rate limit filter, but seeing this config it's simpler enough that I can buy having a separate filter for it. The only thing that would give me pause is whether someone is going to want to match on different types of things (descriptors) and whether we might be better served by constructing a descriptor as a key to a local token bucket? I'm not sure if this is worth it or not but just throwing it out there and I obviously didn't bother doing this for the network rate limit case (albeit a much simpler case). Thoughts?
The local rate limit filter outputs statistics in the *cluster.<route target cluster>.local_ratelimit.* namespace. | ||
429 responses -- or the configured status code -- are emitted to the normal cluster :ref:`dynamic HTTP statistics | ||
<config_cluster_manager_cluster_stats_dynamic_http>`. |
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 think you might want an optional stat prefix here. If you start having multiple per-route configs, it would be very unclear which limit is being hit. Also, I would make sure we are setting the RL access log code also.
* HTTP local rate limit filter. Depending on the route configuration, this filter calls consults | ||
* with local token bucket before allowing further filter iteration. | ||
*/ | ||
class Filter : public Http::StreamFilter { |
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.
Use the pass through filter here as the base class.
// This field allows to send a HTTP response status code to the downstream client other | ||
// than 429 (TooManyRequests) when the request has been rate limited. | ||
type.HttpStatus status = 1; | ||
|
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 have some questions and discussed by #10813.
// This field allows to send a HTTP response status code to the downstream client other | ||
// than 429 (TooManyRequests) when the request has been rate limited. | ||
type.v3.HttpStatus status = 1; |
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.
Sorry, Whether the status
field could be set to universal? Then the rate-limit
filter module convert status-code depends on the requeste protocol. Here is a discuss #10813 .
This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
This pull request has been automatically closed because it has not had activity in the last 14 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
This is just the config API with an overview doc. Implementation
will follow, once we have an agreement.
See #10813.
Signed-off-by: Raul Gutierrez Segales rgs@pinterest.com