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
RateLimiterfilter to create distinct throttling strategies with varyinglimitForPeriod,limitRefreshPeriod, andtimeoutDurationvalues. - Set a
defaultPolicyRefto ensure unmatched URL rules still undergo rate limiting. - Reference policies via
policyRefin URL rules to bind specific strategies to endpoint patterns, methods, or exact paths. - The filter creates isolated limiters per rule using
bindPolicyToURLandcreateRateLimiter, 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →