Rate limiting caps the number of requests a client can send to a server in a given period, such as 300 per minute or 10 per second. Use ASMGlobalRateLimiter in Alibaba Cloud Service Mesh (ASM) to apply global rate limits to inbound traffic of application services with injected sidecars.
Envoy proxies implement rate limiting in two ways: global rate limiting and local rate limiting. This topic covers global rate limiting only. For rate limiting concepts and instructions for local rate limiting, see Configure local rate limiting in the Traffic Management Center.
Two scenarios in this topic show the granularities that a global rate limit can apply to an application service: all requests on a service port (Scenario 1), or only the requests that access a specific path on that port (Scenario 2). Both scenarios use the same ASMGlobalRateLimiter resource name (global-svc-test) and the same ConfigMap (ratelimit-config).
Prerequisites
A Container Service for Kubernetes (ACK) managed cluster is added to the ASM instance, and the ASM instance is of version 1.18.X.XXX or later. For instructions, see Add a cluster to an ASM instance.
Automatic sidecar proxy injection is enabled for the
defaultnamespace in the Kubernetes cluster. For instructions, see Enable automatic sidecar proxy injection.An ingress gateway named ingressgateway is created, and port 80 is enabled on it. For instructions, see Create an ingress gateway.
The httpbin and sleep sample applications are deployed. For instructions, see Deploy the httpbin application in a cluster on the data plane and Deploy the sleep service in a cluster on the data plane.
ASM supports configuring global rate limiting for inbound traffic to ingress gateways and to application services with injected sidecars in version 1.18.0.131 and later. The limit_overrides field, which Scenario 2 uses to rate-limit a specific path, is supported only by ASM instances of version 1.19.0 or later.
Deploy the rate-limiting service
Global rate limiting takes effect only after the rate-limiting service runs in the cluster on the data plane. Deploy the rate-limiting service and the Redis service that it depends on before you configure a rate limiting rule.
Create a file named
ratelimit-svc.yamlwith the following content.apiVersion: v1 kind: ServiceAccount metadata: name: redis --- apiVersion: v1 kind: Service metadata: name: redis labels: app: redis spec: ports: - name: redis port: 6379 selector: app: redis --- apiVersion: apps/v1 kind: Deployment metadata: name: redis spec: replicas: 1 selector: matchLabels: app: redis template: metadata: labels: app: redis sidecar.istio.io/inject: "false" spec: containers: - image: redis:alpine imagePullPolicy: Always name: redis ports: - name: redis containerPort: 6379 restartPolicy: Always serviceAccountName: redis --- apiVersion: v1 kind: ConfigMap metadata: name: ratelimit-config data: config.yaml: | {} --- apiVersion: v1 kind: Service metadata: name: ratelimit labels: app: ratelimit spec: ports: - name: http-port port: 8080 targetPort: 8080 protocol: TCP - name: grpc-port port: 8081 targetPort: 8081 protocol: TCP - name: http-debug port: 6070 targetPort: 6070 protocol: TCP selector: app: ratelimit --- apiVersion: apps/v1 kind: Deployment metadata: name: ratelimit spec: replicas: 1 selector: matchLabels: app: ratelimit strategy: type: Recreate template: metadata: labels: app: ratelimit sidecar.istio.io/inject: "false" spec: containers: # Latest image from https://hub.docker.com/r/envoyproxy/ratelimit/tags - image: envoyproxy/ratelimit:e059638d imagePullPolicy: Always name: ratelimit command: ["/bin/ratelimit"] env: - name: LOG_LEVEL value: debug - name: REDIS_SOCKET_TYPE value: tcp - name: REDIS_URL value: redis:6379 - name: USE_STATSD value: "false" - name: RUNTIME_ROOT value: /data - name: RUNTIME_SUBDIRECTORY value: ratelimit - name: RUNTIME_WATCH_ROOT value: "false" - name: RUNTIME_IGNOREDOTFILES value: "true" ports: - containerPort: 8080 - containerPort: 8081 - containerPort: 6070 volumeMounts: - name: config-volume # $RUNTIME_ROOT/$RUNTIME_SUBDIRECTORY/$RUNTIME_APPDIRECTORY/config.yaml mountPath: /data/ratelimit/config volumes: - name: config-volume configMap: name: ratelimit-configIn the kubeconfig context of the ACK cluster, run the following command to create the rate-limiting service and the Redis service that it depends on in the cluster.
kubectl apply -f ratelimit-svc.yaml
Use the ASM-managed rate-limiting service (optional)
This feature is supported only by ASM instances of version 1.25 or later. If your ASM instance is of a version earlier than 1.25, continue to deploy the rate-limiting service as described earlier and manually update the ConfigMap used by the rate-limiting service.
In ASM 1.25 and later, you can use ASMMeshConfig to enable the ASM-managed rate-limiting service. When you use this method, you do not need to configure rateLimitService when you create an ASMGlobalRateLimiter. ASM automatically uses the rate-limiting service delivered to the clusters on the data plane and automatically updates the ConfigMap used by the rate-limiting service based on the global rate limiting rules.
Prepare the Redis on which the rate-limiting service depends. ASM deploys the rate-limiting service but does not deploy Redis. You can continue to use the Redis deployed earlier or use an existing Redis instance. To continue using
ratelimit-svc.yamlfrom the preceding steps, deploy only the ServiceAccount, Service, and Deployment of Redis in it. Do not deploy theratelimit-configConfigMap, theratelimitService, or theratelimitDeployment.In the kubeconfig context of the ASM instance, run the following command to verify that ASMMeshConfig/default exists.
kubectl get asmmeshconfig defaultCreate a file named
ratelimit-service-patch.yaml. The following example uses the Redis deployed in thedefaultnamespace in the preceding steps.spec: rateLimitService: enabled: true replicas: 1 redis: type: single url: redis.default.svc.cluster.local:6379Run the following command to enable the rate-limiting service with a merge patch to avoid overwriting other settings in ASMMeshConfig/default.
kubectl patch asmmeshconfig default \ --type=merge \ --patch-file ratelimit-service-patch.yamlIn this configuration,
enabledmust be set totrue.replicasspecifies the number of replicas of the rate-limiting service.redis.typesupportssingle,cluster, andsentinel.redis.urlmust be a Redis address that is accessible from the rate-limiting service in the cluster on the data plane.When you create an ASMGlobalRateLimiter in the scenarios that follow, remove the
spec.rateLimitServicefield entirely. Do not configure an empty object such asrateLimitService: {}. Keep the other rate limiting rule settings unchanged.If you omit
spec.rateLimitService, ASM usesratelimit.istio-system.svc.cluster.local:8081by default and automatically creates or updates theistio-system/ratelimit-service-configConfigMap in the ACK cluster. This ConfigMap is managed by ASM. Do not modify it manually.In the kubeconfig context of the ACK cluster, run the following command to view the automatically generated rate limiting configuration.
kubectl -n istio-system get configmap ratelimit-service-config -o yaml
The scenarios that follow still demonstrate the manual deployment method that is compatible with all ASM versions. If you use the ASM-managed rate-limiting service, omit rateLimitService as described in this section and skip the steps that copy the configuration from the status field and manually update the ConfigMap. All other rate limiting rule settings and verification methods remain unchanged.
Scenario 1: Configure global rate limiting for a service port
Apply a rate limit to port 8000 of the httpbin service. After you create the rate limiting rule, the rate limit applies to all requests that are sent to port 8000 of the httpbin service.
Create a file named
global-ratelimit-svc.yamlwith the following content.apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMGlobalRateLimiter metadata: name: global-svc-test namespace: default spec: workloadSelector: labels: app: httpbin rateLimitService: host: ratelimit.default.svc.cluster.local port: 8081 timeout: seconds: 5 isGateway: false configs: - name: httpbin limit: unit: MINUTE quota: 1 match: vhost: name: '*' port: 8000The following table describes some of the fields. For a description of all fields, see ASMGlobalRateLimiter fields.
Parameter
Description
workloadSelectorMatches the workload on which the rate limit takes effect. In this scenario, global rate limiting takes effect on the workload of the httpbin service, so the value is set to
app: httpbin.isGatewaySpecifies whether the configuration applies to a gateway. In this example, the value is set to
false.rateLimitServiceThe domain name, port, and connection timeout settings of the rate-limiting service. For the rate-limiting service deployed in Deploy the rate-limiting service, use the configuration that follows this table.
limitThe rate limiting parameters to take effect.
unitspecifies the time unit of rate limit detection, andquotaspecifies the total number of requests allowed within one unit of time. This example setsunittoMINUTEandquotato1, which means that only one request per minute can be sent on the matched route. Excess requests are rate-limited.vhostThe domain name and route settings that the rate limit matches. When the configuration takes effect on an application service, set
nameto'*'and setportto the Service port of the service.Use the following
rateLimitServiceconfiguration:host: ratelimit.default.svc.cluster.local port: 8081 timeout: seconds: 5In the kubeconfig context of the ASM instance, run the following command to create a global rate limiting rule that takes effect on inbound traffic to the httpbin application service.
kubectl apply -f global-ratelimit-svc.yamlRun the following command to obtain the reconciled configuration of the global rate limiting rule.
kubectl get asmglobalratelimiter global-svc-test -o yamlapiVersion: istio.alibabacloud.com/v1 kind: ASMGlobalRateLimiter metadata: name: global-svc-test namespace: default spec: configs: - limit: quota: 1 unit: MINUTE match: vhost: name: '*' port: 8000 name: httpbin isGateway: false rateLimitService: host: ratelimit.default.svc.cluster.local port: 8081 timeout: seconds: 5 workloadSelector: labels: app: httpbin status: config.yaml: | descriptors: - key: generic_key rate_limit: requests_per_unit: 1 unit: MINUTE value: RateLimit[global-svc-test.default]-Id[3833670472] domain: ratelimit.default.svc.cluster.local message: ok status: successfulCreate a file named
ratelimit-config.yamlto hold the configuration of the global rate-limiting service. Paste the string in theconfig.yamlfield under thestatusfield of the ASMGlobalRateLimiter resource, as it is, into theconfig.yamlfield of the same name underdatain the ConfigMap. This ConfigMap has the same name as theratelimit-configConfigMap inratelimit-svc.yaml, so the pasted string replaces the initial empty configuration ({}).apiVersion: v1 kind: ConfigMap metadata: name: ratelimit-config data: config.yaml: | descriptors: - key: generic_key rate_limit: requests_per_unit: 1 unit: MINUTE value: RateLimit[global-svc-test.default]-Id[3833670472] domain: ratelimit.default.svc.cluster.localThe values in this sample come from the expected output in the previous step. Use the values returned for your own ASMGlobalRateLimiter resource, including the
Idvalue invalue.In the kubeconfig context of the ACK cluster, run the following command to update the configuration of the global rate-limiting service in the cluster.
kubectl apply -f ratelimit-config.yamlRun the following command to start a bash session in the sleep application.
kubectl exec -it deploy/sleep -- shRun the following command to access the httpbin service twice in a row.
curl httpbin:8000/get -v curl httpbin:8000/get -vThe first request is allowed. The following output is returned for the second request:
< HTTP/1.1 429 < x-envoy-ratelimited: true < x-ratelimit-limit: 1, 1;w=60 < x-ratelimit-remaining: 0 < x-ratelimit-reset: 5 < date: Thu, 26 Oct 2023 04:23:54 GMT < server: envoy < content-length: 0 < x-envoy-upstream-service-time: 2 < * Connection #0 to host httpbin left intactThe global rate limiting configuration allows only one request to the httpbin service within one minute, so the second request is rate-limited. Global rate limiting now takes effect on inbound traffic to the httpbin service port.
Scenario 2: Configure global rate limiting for a specific path on a service port
Apply a rate limit to port 8000 of the httpbin service, and restrict the rate limit so that it takes effect only on requests that access the /headers path. After you create the rate limiting rule, the rate limit applies to all requests that are sent to port 8000 of the httpbin service and that access the /headers path.
Create a file named
global-ratelimit-svc.yamlwith the content that matches your ASM version.YAML for ASM versions earlier than 1.19.0
apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMGlobalRateLimiter metadata: name: global-svc-test namespace: default spec: workloadSelector: labels: app: httpbin rateLimitService: host: ratelimit.default.svc.cluster.local port: 8081 timeout: seconds: 5 isGateway: false configs: - name: httpbin limit: unit: MINUTE quota: 1 match: vhost: name: '*' port: 8000 route: header_match: - name: ":path" prefix_match: "/headers"YAML for ASM version 1.19.0 or later
apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMGlobalRateLimiter metadata: name: global-svc-test namespace: default spec: workloadSelector: labels: app: httpbin rateLimitService: host: ratelimit.default.svc.cluster.local port: 8081 timeout: seconds: 5 isGateway: false configs: - name: httpbin limit: unit: SECOND quota: 100000 match: vhost: name: '*' port: 8000 limit_overrides: - request_match: header_match: - name: ":path" prefix_match: "/headers" limit: unit: MINUTE quota: 1The following table describes some of the fields. For a description of all fields, see ASMGlobalRateLimiter fields.
Parameter
Description
workloadSelectorMatches the workload on which the rate limit takes effect. In this scenario, global rate limiting takes effect on the workload of the httpbin service, so the value is set to
app: httpbin.isGatewaySpecifies whether the configuration applies to a gateway. In this example, the value is set to
false.rateLimitServiceThe domain name, port, and connection timeout settings of the rate-limiting service. For the rate-limiting service deployed in Deploy the rate-limiting service, use the configuration that follows this table.
limitThe rate limiting parameters to take effect.
unitspecifies the time unit of rate limit detection, andquotaspecifies the total number of requests allowed within one unit of time. For ASM instances of a version earlier than 1.19.0, this example setsunittoMINUTEandquotato1, which means that only one request per minute can be sent on the matched route, and excess requests are rate-limited. For ASM instances of version 1.19.0 or later, the rate limiting parameters are set to 100,000 requests per second, which is roughly equivalent to no rate limiting, because the rate limit for requests that meet specific conditions takes effect in thelimit_overridesfield.vhostThe domain name and route settings that the rate limit matches. When the configuration takes effect on an application service, set
nameto'*'and setportto the Service port of the service. For ASM instances of a version earlier than 1.19.0, you can also configure header matching rules for requests inroute. This example matches the special header named:path, which matches the path of the request. In other words, the rule matches all requests whose path starts with/headers. For ASM instances of version 1.19.0 or later, the header matching rules for requests are moved fromrouteto thelimit_overridesfield.limit_overridesThe rate limit override configuration, which is supported only by ASM instances of version 1.19.0 or later. It supports matching different attributes of requests and applying a separate rate limiting configuration to the specific requests that are matched. In this example, the
limit_overridesfield specifies matching the special header:path, which matches the path of the request. In other words, the override matches all requests whose path starts with/headers.Use the following
rateLimitServiceconfiguration:host: ratelimit.default.svc.cluster.local port: 8081 timeout: seconds: 5In the kubeconfig context of the ASM instance, run the following command to create a global rate limiting rule that takes effect on inbound traffic to the httpbin application service.
kubectl apply -f global-ratelimit-svc.yamlRun the following command to obtain the reconciled configuration of the global rate limiting rule.
kubectl get asmglobalratelimiter global-svc-test -o yamlapiVersion: istio.alibabacloud.com/v1 kind: ASMGlobalRateLimiter metadata: name: global-svc-test namespace: default spec: configs: - limit: quota: 100000 unit: SECOND limit_overrides: - limit: quota: 1 unit: MINUTE request_match: header_match: - name: :path prefix_match: /headers match: vhost: name: '*' port: 8000 name: httpbin isGateway: false rateLimitService: host: ratelimit.default.svc.cluster.local port: 8081 timeout: seconds: 5 workloadSelector: labels: app: httpbin status: config.yaml: | descriptors: - descriptors: - key: header_match rate_limit: requests_per_unit: 1 unit: MINUTE value: RateLimit[global-svc-test.default]-Id[2613586978] key: generic_key rate_limit: requests_per_unit: 100000 unit: SECOND value: RateLimit[global-svc-test.default]-Id[2613586978] domain: ratelimit.default.svc.cluster.local message: ok status: successfulCreate a file named
ratelimit-config.yamlto hold the configuration of the global rate-limiting service. Paste the string in theconfig.yamlfield under thestatusfield of the ASMGlobalRateLimiter resource, as it is, into theconfig.yamlfield of the same name underdatain the ConfigMap. This ConfigMap has the same name as theratelimit-configConfigMap inratelimit-svc.yaml, so the pasted string replaces the initial empty configuration ({}).apiVersion: v1 kind: ConfigMap metadata: name: ratelimit-config data: config.yaml: | descriptors: - descriptors: - key: header_match rate_limit: requests_per_unit: 1 unit: MINUTE value: RateLimit[global-svc-test.default]-Id[2613586978] key: generic_key rate_limit: requests_per_unit: 100000 unit: SECOND value: RateLimit[global-svc-test.default]-Id[2613586978] domain: ratelimit.default.svc.cluster.localThe values in this sample come from the expected output in the previous step. Use the values returned for your own ASMGlobalRateLimiter resource, including the
Idvalue invalue.In the kubeconfig context of the ACK cluster, run the following command to update the configuration of the global rate-limiting service in the cluster.
kubectl apply -f ratelimit-config.yamlRun the following command to start a bash session in the sleep application.
kubectl exec -it deploy/sleep -- shRun the following command to access the
/headerspath of the httpbin service twice in a row.curl httpbin:8000/headers -v curl httpbin:8000/headers -vThe first request is allowed. The following output is returned for the second request:
< HTTP/1.1 429 Too Many Requests < x-envoy-ratelimited: true < x-ratelimit-limit: 1, 1;w=60 < x-ratelimit-remaining: 0 < x-ratelimit-reset: 5 < date: Thu, 26 Oct 2023 04:23:54 GMT < server: envoy < content-length: 0 < x-envoy-upstream-service-time: 2 < * Connection #0 to host httpbin left intactThe global rate limiting configuration allows only one request to the
/headerspath of the httpbin service within one minute, so the second request is rate-limited. Global rate limiting now takes effect on inbound traffic to the/headerspath of the httpbin service.Run the following command to access the
/getpath of the httpbin service.curl httpbin:8000/get -vExpected output:
* Trying 192.168.243.21:8000... * Connected to httpbin (192.168.243.21) port 8000 (#0) > GET /get HTTP/1.1 > Host: httpbin:8000 > User-Agent: curl/8.1.2 > Accept: */* > < HTTP/1.1 200 OK < server: envoy < date: Thu, 11 Jan 2024 06:25:09 GMT < content-type: application/json < content-length: 431 < access-control-allow-origin: * < access-control-allow-credentials: true < x-envoy-upstream-service-time: 7 < { "args": {}, "headers": { "Accept": "*/*", "Host": "httpbin:8000", "User-Agent": "curl/8.1.2", "X-Envoy-Attempt-Count": "1", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=be10819991ba1a354a89e68b3bed1553c12a4fba8b65fbe0f16299d552680b29;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep" }, "origin": "127.0.0.6", "url": "http://httpbin:8000/get" } * Connection #0 to host httpbin left intactRequests sent to other paths of the httpbin service are not affected by the global rate limiting configuration and can still be accessed normally.
References
For descriptions of the ASMGlobalRateLimiter fields, see ASMGlobalRateLimiter fields.
For more information about how to configure local rate limiting in the Traffic Management Center, see Configure local rate limiting in the Traffic Management Center.
For more information about how to configure global rate limiting for an ingress gateway, see Configure global rate limiting for an ingress gateway.