--- 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.