istio.io/_docs/tasks/rate-limiting.md

216 lines
7.5 KiB
Markdown

---
title: Enabling Rate Limits
overview: This task shows you how to use Istio to dynamically limit the traffic to a service.
order: 80
layout: docs
type: markdown
---
{% include home.html %}
This task shows you how to use Istio to dynamically limit the traffic to a service.
## Before you begin
* Setup Istio by following the instructions in the
[Installation guide](./installing-istio.html).
* Deploy the [BookInfo]({{home}}/docs/samples/bookinfo.html) sample application.
* Initialize the application version routing to direct `reviews` service requests from
test user "jason" to version v2 and requests from any other user to v3.
```bash
istioctl create -f samples/apps/bookinfo/route-rule-reviews-test-v2.yaml
istioctl create -f samples/apps/bookinfo/route-rule-reviews-v3.yaml
```
> Note: if you have conflicting rule that you set in previous tasks,
use `istioctl replace` instead of `istioctl create`.
## Rate limits
Istio enables users to rate limit traffic to a service.
Consider `ratings` as an external paid service like Rotten Tomatoes® with `1qps` free quota.
Using Istio we can ensure that `1qps` is not breached.
1. Point your browser at the BookInfo `productpage` (http://$GATEWAY_URL/productpage).
If you log in as user "jason", you should see black ratings stars with each review,
indicating that the `ratings` service is being called by the "v2" version of the `reviews` service.
If you log in as any other user (or logout) you should see red ratings stars with each review,
indicating that the `ratings` service is being called by the "v3" version of the `reviews` service.
1. Configure mixer with the rate limit.
Save this as ratelimit.yaml:
```yaml
rules:
- aspects:
- kind: quotas
params:
quotas:
- descriptorName: RequestCount
maxAmount: 1
expiration: 1s
```
and then run the following command:
```bash
istioctl mixer rule create global ratings.default.svc.cluster.local -f ratelimit.yaml
```
`istioctl` sets configuration for `subject=ratings.default.svc.cluster.local`
1. Generate load on the `productpage` with the following command:
```bash
while true; do curl -s -o /dev/null http://$GATEWAY_URL/productpage; done
```
1. Refresh the `productpage` in your browser.
While the load generator is running (i.e., generating more than 1 req/s), the traffic generated by
your browser will be rate limited.
Notice that if you log in as user "jason" or any other user, the `reviews` service is unable to
access the `ratings` service, so you stop seeing stars, red or black.
## Conditional rate limits
In the previous example we applied a rate limit to the `ratings` service without regard
to any other attributes. It is possible to conditionally apply rate limits based on
attributes like the source of the traffic.
The following configuration applies a `1qps` rate limit only to version `v3` of `reviews`.
1. Configure mixer with the conditional rate limit.
Save this as ratelimit-conditional.yaml:
```yaml
rules:
- selector: source.labels["app"]=="reviews" && source.labels["version"] == "v3"
aspects:
- kind: quotas
params:
quotas:
- descriptorName: RequestCount
maxAmount: 1
expiration: 1s
```
and then run the following command:
```bash
istioctl mixer rule create global ratings.default.svc.cluster.local -f ratelimit-conditional.yaml
```
Notice the rule is the same as the previous example, only this one uses a `selector` to
apply the ratelimit only for requests from `reviews:v3`.
1. Generate load on the `productpage` with the following command:
```bash
while true; do curl -s -o /dev/null http://$GATEWAY_URL/productpage; done
```
1. Refresh the `productpage` in your browser.
As in the previous example, while the load
generator is running (i.e., generating more than 1 req/s), the traffic generated by
your browser will be rate limited, but this time only if the request is from `reviews:v3`.
Notice that this time if you log in as user "jason" (the `reviews:v2` user) you will continue to see
the black ratings stars. Only the other users will stop seeing
the red ratings stars while the load generator is running.
## Understanding rate limits
In the preceding examples we saw how Mixer applies rate limits to requests that match certain conditions.
Every distinct rate limit configuration represents a counter. If the number
of requests in the last `expiration` duration exceed `maxAmount`, Mixer returns a `RESOURCE_EXHAUSTED`
message to the proxy. The proxy in turn returns status `HTTP 429` to the caller.
Multiple rate limits may apply to the same request.
Mixer `MemQuota` adapter uses a sliding window of sub second resolution to enforce rate limits.
Consider the following example
```yaml
descriptorName: RequestCount
maxAmount: 5000
expiration: 5s
labels:
label1: target.service
```
This defines a set of counters with a limit of `5000` per every `5 seconds`.
Individual counters within the set are identified by unique keys. A key is formed on the request path by using all parameters
of the configuration. Here we introduce the notion of labels that enable creation of more granular counter keys.
When a request arrives at Mixer with `target.service=ratings` it forms the following counter key.
```$aspect_id;RequestCount;maxAmount=5000;expiration=5s;label1=ratings ```
Using `target.service` in the counter key enables independent rate limits for every service.
In absence of `target.service` as part of the key, the same counter location is used by all services resulting in
combined rate limit of `5000` requests per `5 seconds`
Mixer supports an arbitrary number of labels by defining `QuotaDescriptors`.
```yaml
name: RequestCount
rate_limit: true
labels:
label1: 1 # STRING
```
Here we define `RequestCount` quota descriptor that takes 1 string label. We recommend using meaningful label names
even though label names are arbitrary.
```yaml
name: RequestCount_byService_byUser
rate_limit: true
labels:
service: 1 # STRING
user: 1 # STRING
```
Mixer expects `user,service` labels when the `RequestCount_byService_byUser` descriptor is used and produces
the following config validation error if any labels are missing.
```bash
* quotas: aspect validation failed: 1 error occurred:
* quotas[RequestCount_byService_byUser].labels: wrong dimensions: descriptor expects 2 labels, found 0 labels
```
## Cleanup
* Remove the mixer configuration rule:
```bash
istioctl mixer rule create global ratings.default.svc.cluster.local -f samples/apps/bookinfo/mixer-rule-empty-rule.yaml
```
> Note: removing a rule by setting an empty rule list is a temporary workaround because `istioctl delete` does not
yet support mixer rules.
* Remove the application routing rules:
```
istioctl delete -f samples/apps/bookinfo/route-rule-reviews-test-v2.yaml
istioctl delete -f samples/apps/bookinfo/route-rule-reviews-v3.yaml
```
## What's next
* Learn more about [Mixer]({{home}}/docs/concepts/policy-and-control/mixer.html) and [Mixer Config]({{home}}/docs/concepts/policy-and-control/mixer-config.html).
* Discover the full [Attribute Vocabulary]({{home}}/docs/reference/config/mixer/attribute-vocabulary.html).
* Read the reference guide to [Writing Config]({{home}}/docs/reference/writing-config.html).
* If you are not planning to explore any follow-on tasks, refer to the
[BookInfo cleanup]({{home}}/docs/samples/bookinfo.html#cleanup) instructions
to shutdown the application and cleanup the associated rules.