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

local rate limit HTTP filter: add config interface #10820

Conversation

rgs1
Copy link
Member

@rgs1 rgs1 commented Apr 17, 2020

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

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>
@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/.

🐱

Caused by: #10820 was opened by rgs1.

see: more, trace.

Comment on lines +27 to +29
// 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;
Copy link
Contributor

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?

Copy link
Member Author

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?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, few examples:

  1. There is a single gRPC route /service.Service/Method but it has envoy.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.
  2. 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.

Copy link
Member Author

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?

Copy link
Member

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.

Copy link
Member

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 .

I couldn't get docs to build without the new filter referenced in
source/extensions/extensions_build_config.bzl, so I added the boilerplate
pieces of the filter to get docs built.

Signed-off-by: Raul Gutierrez Segales <rgs@pinterest.com>
@rgs1
Copy link
Member Author

rgs1 commented Apr 17, 2020

@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 RouteAction or a similar core config object?

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>
@rgs1
Copy link
Member Author

rgs1 commented Apr 17, 2020

@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 RouteAction or a similar core config object?

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?

cc: @euroelessar on this too

@euroelessar
Copy link
Contributor

@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 RouteAction or a similar core config object?

It feels to me that it should be a separate filter/extension, what are the reasons it needs to be a part of the Router itself?

@rgs1
Copy link
Member Author

rgs1 commented Apr 17, 2020

@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 RouteAction or a similar core config object?

It feels to me that it should be a separate filter/extension, what are the reasons it needs to be a part of the Router itself?

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 :-)

@mattklein123 mattklein123 self-assigned this Apr 18, 2020

api_proto_package(
deps = [
"//envoy/api/v2/core:pkg",
Copy link
Member

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.

Copy link
Member Author

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
Copy link
Member

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.

Copy link
Member Author

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}];
}
Copy link
Member

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.

Copy link
Member Author

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?

Copy link
Member

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?

Copy link
Member

@mattklein123 mattklein123 left a 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}];
Copy link
Member

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?

Comment on lines +27 to +29
// 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;
Copy link
Member

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}];
}
Copy link
Member

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?

Comment on lines +23 to +25
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>`.
Copy link
Member

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 {
Copy link
Member

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;

Copy link
Member

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.

Comment on lines +27 to +29
// 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;
Copy link
Member

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 .

@stale
Copy link

stale bot commented Apr 29, 2020

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!

@stale stale bot added the stale stalebot believes this issue/PR has not been touched recently label Apr 29, 2020
@stale
Copy link

stale bot commented May 6, 2020

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!

@stale stale bot closed this May 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api stale stalebot believes this issue/PR has not been touched recently waiting
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants