How to Configure Rate Limiting with Multiple Strategies in Easegress

To configure rate limiting with multiple strategies in Easegress, define distinct policies in the RateLimiter filter, set a default fallback, and bind specific policies to URL rules using policyRef so different endpoints can enforce different throttling behaviors.

The Easegress traffic gateway provides sophisticated rate limiting capabilities through its RateLimiter filter, allowing operators to apply distinct throttling strategies to different API endpoints or user groups. By leveraging multiple policies within a single filter instance, you can enforce strict burst limits on sensitive endpoints while maintaining generous throughput for public APIs, all within the megaease/easegress open-source framework.

How the RateLimiter Filter Works

The RateLimiter filter in pkg/filters/ratelimiter/ratelimiter.go implements request throttling using a token-bucket algorithm provided by the underlying librl package. When processing traffic, the filter evaluates incoming requests against configured URL rules, binds the appropriate policy to each rule via bindPolicyToURL, and creates an isolated librl.RateLimiter instance for every unique rule combination.

During request handling, the filter calls AcquirePermission on the matched limiter. The request either proceeds immediately, waits for the specified timeoutDuration, or receives a 429 Too Many Requests response if the limit is exceeded.

Configuring Multiple Rate Limiting Strategies

To implement differentiated rate limiting across your API surface, you must define multiple policies and explicitly reference them in your URL rules.

Define Distinct Policies

Each policy describes a throttling strategy using three key parameters: limitForPeriod (maximum requests), limitRefreshPeriod (token refill interval), and timeoutDuration (maximum wait time). In pkg/filters/ratelimiter/ratelimiter.go, the filter parses these definitions and validates them during initialization.

Set a Default Fallback

The defaultPolicyRef field specifies which policy to apply when a URL rule omits the policyRef attribute. This ensures every matched request undergoes rate limiting even without explicit policy assignment.

Create URL Rules with Policy References

URL rules match requests by HTTP method, exact path, path prefix, or regex pattern. Each rule optionally includes a policyRef that links to one of your defined policies. The bindPolicyToURL function (lines 64-73 in pkg/filters/ratelimiter/ratelimiter.go) resolves these references during filter initialization, falling back to the default policy when policyRef is empty.

Complete Configuration Example

The following YAML configuration demonstrates two distinct strategies: a strict policy for administrative endpoints and a permissive policy for high-traffic public APIs.

- name: rateLimiter
  kind: RateLimiter
  policies:
  - name: strict-policy
    timeoutDuration: 1000ms
    limitRefreshPeriod: 5000ms
    limitForPeriod: 2
  - name: permissive-policy
    timeoutDuration: 100ms
    limitRefreshPeriod: 10ms
    limitForPeriod: 30
  defaultPolicyRef: strict-policy
  urls:
  - methods: [GET, POST, PUT, DELETE]
    url:
      regex: ^/admin/.+$
    policyRef: strict-policy
  - methods: [GET, POST]
    url:
      exact: /api/v1/high-traffic
    policyRef: permissive-policy

This example, adapted from example/config/pipeline-example.yaml, creates a token bucket that allows only 2 requests per 5 seconds for admin endpoints, while permitting 30 requests per 10 milliseconds for the specific high-traffic endpoint.

Implementation Details

Understanding the internal wiring helps troubleshoot configuration issues and optimize performance.

Policy Binding Mechanism

When the filter initializes, it iterates through URL rules and executes the bindPolicyToURL method to attach the correct policy struct to each rule:

func (rl *RateLimiter) bindPolicyToURL(u *URLRule) {
    name := u.PolicyRef
    if name == "" {
        name = rl.spec.DefaultPolicyRef
    }
    for _, p := range rl.spec.Policies {
        if p.Name == name {
            u.policy = p
            break
        }
    }
}

Source: pkg/filters/ratelimiter/ratelimiter.go lines 64-73.

Limiter Initialization

Each URL rule instantiates its own rate limiter via the createRateLimiter method, which translates the policy parameters into the underlying library configuration:

func (url *URLRule) createRateLimiter() {
    policy := librl.Policy{
        LimitForPeriod: url.policy.LimitForPeriod,
    }
    if policy.LimitForPeriod == 0 { policy.LimitForPeriod = 50 }
    if d := url.policy.TimeoutDuration; d != "" {
        policy.TimeoutDuration, _ = time.ParseDuration(d)
    } else {
        policy.TimeoutDuration = 100 * time.Millisecond
    }
    if d := url.policy.LimitRefreshPeriod; d != "" {
        policy.LimitRefreshPeriod, _ = time.ParseDuration(d)
    } else {
        policy.LimitRefreshPeriod = 10 * time.Millisecond
    }
    url.rl = librl.New(&policy)
}

Source: pkg/filters/ratelimiter/ratelimiter.go lines 13-34.

The core token-bucket algorithm resides in pkg/util/ratelimiter/ratelimiter.go, implementing the actual permission acquisition logic that the filter invokes.

Summary

  • Define multiple policies in the RateLimiter filter to create distinct throttling strategies with varying limitForPeriod, limitRefreshPeriod, and timeoutDuration values.
  • Set a defaultPolicyRef to ensure unmatched URL rules still undergo rate limiting.
  • Reference policies via policyRef in URL rules to bind specific strategies to endpoint patterns, methods, or exact paths.
  • The filter creates isolated limiters per rule using bindPolicyToURL and createRateLimiter, enabling fine-grained traffic shaping without cross-contamination between endpoints.

Frequently Asked Questions

What happens if a URL rule does not specify a policyRef?

If a URL rule omits the policyRef field, the filter automatically uses the policy defined in defaultPolicyRef. If neither is specified, the rule may not enforce rate limiting unless the implementation provides internal defaults, though best practice requires explicit configuration.

Can I use regex patterns to apply different rate limits to API versions?

Yes. The url.regex field accepts standard regular expressions, allowing you to match patterns like ^/api/v1/.+$ for version 1 and ^/api/v2/.+$ for version 2, each referencing different policies to enforce version-specific throughput limits.

How does the timeoutDuration parameter affect client experience?

The timeoutDuration specifies how long a request waits for a token to become available before receiving a 429 Too Many Requests response. Longer durations increase queueing time but improve success rates for bursty traffic, while zero or short durations fail fast during congestion.

Is there a performance overhead when using many URL rules?

Each URL rule creates an independent librl.RateLimiter instance during initialization, so memory usage scales linearly with rule count. However, the lookup operation during request handling uses efficient matching, and the per-rule isolation prevents rate limit contention between different API groups.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →