Help Center/ Cloud Container Engine/ User Guide/ Networking/ Gateway API/ Using Envoy Gateway for Rate Limiting
Updated on 2026-06-16 GMT+08:00

Using Envoy Gateway for Rate Limiting

Rate limiting is a protection mechanism that controls the rate at which clients send requests to a server. Its core purpose is to prevent system overload from burst traffic and ensure service stability and availability. It is typically expressed as a request quota within a specific time window, for example, 100 requests per minute or 10 requests per second.

Envoy proxies enforce rate limits in two ways: local and global. The key difference is the statistical scope: In local rate limiting, each Envoy instance counts requests independently. In global rate limiting, all Envoy instances share a single request counter. For example, if a Gateway with five Envoy instances is deployed and a rate limit of 100 requests per minute is configured, the effects differ significantly:

  • Local rate limiting: Each Envoy instance counts requests independently. Consequently, a Gateway with five Envoy instances can theoretically process up to 500 (5 × 100) requests per minute. This results in significantly higher backend load than intended.
  • Global rate limiting: All Envoy instances share a single request counter. Redis serves as a centralized, high-performance distributed counter, enforcing a globally unified quota regardless of which Envoy instance receives the request. This enables precise cross-instance rate limiting. Total traffic is strictly capped at 100 requests per minute, regardless of the number of Envoy instances.

    Envoy Gateway supports global rate limiting. When enabled, a rate limiting service is automatically deployed. This service centrally manages global rate limiting policies and real-time traffic data, and enforces rate limits on incoming requests based on the configured policies.

This section provides configuration examples for global and local rate limiting in different scenarios. For complete rate limiting policy parameters, see BackendTrafficPolicy.

Precautions

Before disabling global rate limiting, ensure that all global rate limiting policies have been deleted. Otherwise, route access will fail. For details, see How to Disable Global Rate Limiting?.

Prerequisites

  • Envoy Gateway has been installed in the current cluster and is running.
  • A backend application and its Service are running in the cluster.
    In this example, the backend application is Nginx, the Service name is backend, and the Service port is 3000. Save the following YAML as backend.yaml and run kubectl apply -f backend.yaml:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: backend
      namespace: default
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: backend
          version: v1
      template:
        metadata:
          labels:
            app: backend
            version: v1
        spec:
          containers:
            - name: container-1
              image: nginx:latest
          imagePullSecrets:
            - name: default-secret
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: backend
      labels:
        app: backend
        version: v1
      namespace: default
    spec:
      selector:
        app: backend
        version: v1
      ports:
        - name: cce-service-0
          targetPort: 80
          port: 3000
          protocol: TCP
      type: ClusterIP

Creating a Global Rate Limiting Policy

Global rate limiting in Envoy Gateway relies on Redis as a centralized counter to aggregate and enforce real-time traffic quotas across multiple Envoy Gateway instances. This section uses a self-managed Redis service.

Step 1: Deploy Redis

  1. Use kubectl to access the cluster. For details, see Accessing a Cluster Using kubectl.
  2. Create redis-service.yaml.

    kind: Namespace
    apiVersion: v1
    metadata:
      name: redis-system
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: redis
      namespace: redis-system
      labels:
        app: redis
    spec:
      serviceName: "redis"
      replicas: 1
      selector:
        matchLabels:
          app: redis
      template:
        metadata:
          labels:
            app: redis
        spec:
          containers:
            - image: redis:latest
              name: redis
              ports:
                - containerPort: 6379
              resources:
                limits:
                  cpu: 1500m
                  memory: 512Mi
                requests:
                  cpu: 200m
                  memory: 256Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: redis
      namespace: redis-system
      labels:
        app: redis
    spec:
      ports:
        - name: redis
          port: 6379
          protocol: TCP
          targetPort: 6379
      selector:
        app: redis

  3. Deploy the Redis service.

    kubectl apply -f redis-service.yaml

Step 2: Enable Global Rate Limiting for the Add-on

  1. Log in to the CCE console and click the cluster name to access the cluster console.
  2. In the navigation pane, choose Add-ons. On the displayed page, locate Envoy Gateway and click Edit.
  3. Enable global rate limiting and configure the Redis service address.

    In this example, the Redis service in the cluster is accessible at redis.redis-system.svc.cluster.local:6379.

  4. Click OK.

Step 3: Create a Gateway and an HTTPRoute

Create a Gateway and an HTTPRoute. The rate limiting policies will be applied to this HTTPRoute.

  1. Create ratelimit.yaml.

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: my-gateway              # Gateway name
      namespace: default
    spec:
      gatewayClassName: envoy-gateway  # GatewayClass name
      listeners:
        - name: http                                     
          protocol: HTTP               # Protocol
          port: 80                     # Listener port
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute                # The resource type is HTTPRoute.
    metadata:
      name: ratelimit                # HTTPRoute name
      namespace: default
    spec:
      parentRefs:
        - name: my-gateway  # Gateway name
      hostnames:
        - "www.example.com"    # Domain name
      rules:
        - backendRefs:
            - group: ""
              kind: Service
              name: backend       # Name of the existing Service
              port: 3000          # Service port
              weight: 1

  2. Deploy the Gateway and HTTPRoute.

    kubectl apply -f ratelimit.yaml

Step 4: Create a Rate Limiting Policy (BackendTrafficPolicy)

  • Scenario 1: Limiting request frequency
  • Scenario 2: Rate limiting for a specific user
  • Scenario 3: Rate limiting for all users except a specific one
  • Scenario 4: Rate limiting based on client IP addresses (supported only in CCE Turbo clusters using dedicated load balancers)

Creating a Local Rate Limiting Policy

Local rate limiting policies do not depend on Redis. Each Envoy instance counts requests independently.

Step 1: Create a Gateway and an HTTPRoute

Create a Gateway and an HTTPRoute. The rate limiting policies will be applied to this HTTPRoute.

  1. Create ratelimit.yaml.

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: my-gateway              # Gateway name
      namespace: default
    spec:
      gatewayClassName: envoy-gateway  # GatewayClass name
      listeners:
        - name: http                                     
          protocol: HTTP               # Protocol
          port: 80                     # Listener port
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute                # The resource type is HTTPRoute.
    metadata:
      name: ratelimit                # HTTPRoute name
      namespace: default
    spec:
      parentRefs:
        - name: my-gateway  # Gateway name
      hostnames:
        - "www.example.com"    # Domain name
      rules:
        - backendRefs:
            - group: ""
              kind: Service
              name: backend       # Name of the existing Service
              port: 3000          # Service port
              weight: 1

  2. Deploy the Gateway and HTTPRoute.

    kubectl apply -f ratelimit.yaml

Step 2: Create a Rate Limiting Policy (BackendTrafficPolicy)

The scenarios supported by a local rate limiting policy are the same as those supported by a global rate limiting policy. The following example demonstrates how to configure a local rate limiting policy to allow three requests per minute.

  1. Create backendtrafficpolicy.yaml.

    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: BackendTrafficPolicy
    metadata:
      name: multiple-rules-example
      namespace: default
    spec:
      targetRefs:
        - group: gateway.networking.k8s.io
          kind: HTTPRoute
          name: ratelimit  # Name of the HTTPRoute for rate limiting
      rateLimit:
        type: Local  # Local rate limiting policy
        local: # Differs from the global rate limiting policy
          rules:
            # Rate limiting policy, allowing three requests per minute
            - limit:
                requests: 3
                unit: Minute

  2. Deploy the rate limiting policy.

    kubectl apply -f backendtrafficpolicy.yaml

  3. Change the number of Envoy pods.

    1. Log in to the CCE console and click the cluster name to access the cluster console.
    2. In the navigation pane, choose Add-ons. On the displayed page, locate Envoy Gateway and click Edit.
    3. Change the number of Envoy pods to 2.

    4. Click OK.

  4. Test the request rate limiting.

    for i in {1..8}; do curl -I --header "Host: www.example.com"  http://xx.xx.xx.xx/ ; sleep 1; done

    Expected output:

    HTTP/1.1 200 OK
    server: nginx/1.23.2
    date: Sat, 30 May 2026 08:40:34 GMT
    content-type: text/html
    content-length: 615
    last-modified: Wed, 19 Oct 2022 07:56:21 GMT
    etag: "634fada5-267"
    accept-ranges: bytes
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 2
    x-ratelimit-reset: 0
    
    HTTP/1.1 200 OK
    server: nginx/1.23.2
    date: Sat, 30 May 2026 08:40:35 GMT
    content-type: text/html
    content-length: 615
    last-modified: Wed, 19 Oct 2022 07:56:21 GMT
    etag: "634fada5-267"
    accept-ranges: bytes
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 2
    x-ratelimit-reset: 0
    
    HTTP/1.1 200 OK
    server: nginx/1.23.2
    date: Sat, 30 May 2026 08:40:36 GMT
    content-type: text/html
    content-length: 615
    last-modified: Wed, 19 Oct 2022 07:56:21 GMT
    etag: "634fada5-267"
    accept-ranges: bytes
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 1
    x-ratelimit-reset: 0
    
    HTTP/1.1 200 OK
    server: nginx/1.23.2
    date: Sat, 30 May 2026 08:40:37 GMT
    content-type: text/html
    content-length: 615
    last-modified: Wed, 19 Oct 2022 07:56:21 GMT
    etag: "634fada5-267"
    accept-ranges: bytes
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 1
    x-ratelimit-reset: 0
    
    HTTP/1.1 200 OK
    server: nginx/1.23.2
    date: Sat, 30 May 2026 08:40:38 GMT
    content-type: text/html
    content-length: 615
    last-modified: Wed, 19 Oct 2022 07:56:21 GMT
    etag: "634fada5-267"
    accept-ranges: bytes
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 0
    x-ratelimit-reset: 15
    
    HTTP/1.1 200 OK
    server: nginx/1.23.2
    date: Sat, 30 May 2026 08:40:39 GMT
    content-type: text/html
    content-length: 615
    last-modified: Wed, 19 Oct 2022 07:56:21 GMT
    etag: "634fada5-267"
    accept-ranges: bytes
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 0
    x-ratelimit-reset: 15
    
    HTTP/1.1 429 Too Many Requests
    content-length: 18
    content-type: text/plain
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 0
    x-ratelimit-reset: 13
    date: Sat, 30 May 2026 08:40:40 GMT
    
    HTTP/1.1 429 Too Many Requests
    content-length: 18
    content-type: text/plain
    x-ratelimit-limit: 3
    x-ratelimit-remaining: 0
    x-ratelimit-reset: 13
    date: Sat, 30 May 2026 08:40:41 GMT

    The command output shows that HTTP 200 is returned for the first six requests and HTTP 429 for the seventh and eighth requests, indicating that each of the two Envoy instances allows three requests per minute, for a total of six. The local rate limiting policy is effective.

FAQs

How to Disable Global Rate Limiting?

Before disabling global rate limiting, ensure that all global rate limiting policies have been deleted or converted to local rate limiting policies. To do this, perform the following steps:

  1. Check global rate limiting policies.
    kubectl get backendtrafficpolicy -A -o jsonpath='{range .items[?(@.spec.rateLimit.type=="Global")]}{.metadata.namespace}{"/"}{.metadata.name}{"\n"}{end}'
  2. Delete these policies or convert them to local ones.
    The following example converts a global rate limiting policy to a local one:
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: BackendTrafficPolicy
    metadata:
      name: multiple-rules-example
      namespace: default
    spec:
      targetRefs:
        - group: gateway.networking.k8s.io
          kind: HTTPRoute
          name: ratelimit 
      rateLimit:
        type: Global # Convert it to a local one.
        global:      # Change it to local.
          rules: 
            - limit:
                requests: 3
                unit: Minute
  3. Repeat step 1 to verify the change.