Configure distributed rate limiting across multiple Sentinel instances using Redis or Memcached backends. This example shows how to implement consistent rate limiting in multi-instance deployments.
Use Case
- Rate limit across multiple Sentinel instances
- Per-client, per-API-key, or per-organization limits
- Tiered rate limits for different user types
- Graceful degradation with delay instead of reject
- Fallback to local rate limiting when backend unavailable
Architecture
┌─────────────────┐
│ Clients │
└────────┬────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│Sentinel │ │Sentinel │ │Sentinel │
│ :8080 │ │ :8080 │ │ :8080 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└──────────────────┼──────────────────┘
│
┌───────▼───────┐
│ Redis Cluster │
│ (counters) │
└───────────────┘
Configuration
Create sentinel.kdl:
// Distributed Rate Limiting Configuration
// Multi-instance rate limiting with Redis backend
system {
worker-threads 4
max-connections 10000
}
listeners {
listener "http" {
address "0.0.0.0:8080"
protocol "http"
request-timeout-secs 60
}
}
upstreams {
upstream "api-backend" {
target "10.0.1.10:8080" weight=1
target "10.0.1.11:8080" weight=1
target "10.0.1.12:8080" weight=1
load-balancing "round-robin"
health-check {
type "http" {
path "/health"
expected-status 200
}
interval-secs 10
}
}
upstream "premium-backend" {
target "10.0.2.10:8080" weight=1
target "10.0.2.11:8080" weight=1
load-balancing "least-connections"
}
}
// =============================================================================
// Filter definitions with different rate limit backends
// =============================================================================
filters {
// Redis-backed distributed rate limiting
filter "redis-rate-limit" {
type "rate-limit"
max-rps 100
burst 200
key "client-ip"
on-limit "reject"
// Redis backend for distributed counting
backend "redis"
redis-url "redis://redis-cluster.internal:6379"
redis-prefix "sentinel:ratelimit:"
redis-pool-size 10
redis-timeout-ms 50
redis-fallback-local #true // Fall back to local if Redis unavailable
}
// Redis rate limit with API key as key
filter "redis-api-rate-limit" {
type "rate-limit"
max-rps 1000
burst 2000
key "header:X-API-Key"
on-limit "reject"
backend "redis"
redis-url "redis://redis-cluster.internal:6379"
redis-prefix "sentinel:api-ratelimit:"
redis-pool-size 20
redis-timeout-ms 100
redis-fallback-local #true
}
// Redis rate limit with delay action (graceful degradation)
filter "redis-rate-delay" {
type "rate-limit"
max-rps 50
burst 100
key "client-ip"
on-limit "delay" // Delay instead of reject
max-delay-ms 5000 // Max 5 second delay
backend "redis"
redis-url "redis://redis-cluster.internal:6379"
redis-prefix "sentinel:delay-ratelimit:"
redis-pool-size 10
redis-timeout-ms 50
redis-fallback-local #true
}
// Tiered rate limits
filter "free-tier-limit" {
type "rate-limit"
max-rps 10
burst 20
key "header:X-User-Id"
on-limit "reject"
backend "redis"
redis-url "redis://redis-cluster.internal:6379"
redis-prefix "sentinel:free:"
redis-fallback-local #true
}
filter "premium-tier-limit" {
type "rate-limit"
max-rps 1000
burst 2000
key "header:X-User-Id"
on-limit "reject"
backend "redis"
redis-url "redis://redis-cluster.internal:6379"
redis-prefix "sentinel:premium:"
redis-fallback-local #true
}
// Local rate limiting (single instance only)
filter "local-rate-limit" {
type "rate-limit"
max-rps 1000
burst 2000
key "client-ip"
on-limit "reject"
backend "local"
}
}
routes {
// Public API with Redis rate limiting
route "public-api" {
priority "normal"
matches {
path-prefix "/api/public"
}
upstream "api-backend"
filters "redis-rate-limit"
policies {
timeout-secs 30
failure-mode "open"
}
}
// Authenticated API with API key rate limiting
route "authenticated-api" {
priority "high"
matches {
path-prefix "/api/v1"
header "X-API-Key"
}
upstream "api-backend"
filters "redis-api-rate-limit"
policies {
timeout-secs 30
failure-mode "closed"
}
}
// Tiered API access
route "free-tier-api" {
priority "normal"
matches {
path-prefix "/api"
header "X-User-Tier" "free"
}
upstream "api-backend"
filters "free-tier-limit"
policies {
timeout-secs 30
}
}
route "premium-tier-api" {
priority "high"
matches {
path-prefix "/api"
header "X-User-Tier" "premium"
}
upstream "premium-backend"
filters "premium-tier-limit"
policies {
timeout-secs 60
}
}
// Rate limit with delay (graceful degradation)
route "graceful-api" {
priority "normal"
matches {
path-prefix "/api/graceful"
}
upstream "api-backend"
filters "redis-rate-delay"
policies {
timeout-secs 35 // Account for potential delay
}
}
// Layered rate limits (multiple filters)
route "layered-rate-limit" {
priority "high"
matches {
path-prefix "/api/protected"
}
upstream "api-backend"
// Apply both per-IP and per-API-key limits
filters "redis-rate-limit" "redis-api-rate-limit"
policies {
timeout-secs 30
failure-mode "closed"
}
}
// Health check (no rate limiting)
route "health" {
priority "critical"
matches {
path "/health"
}
builtin-handler "health"
}
}
observability {
metrics {
enabled #true
address "0.0.0.0:9090"
path "/metrics"
// Rate limit metrics:
// - sentinel_rate_limit_requests_total
// - sentinel_rate_limit_limited_total
// - sentinel_rate_limit_backend_latency_seconds
// - sentinel_rate_limit_fallback_total
}
logging {
level "info"
format "json"
access-log {
enabled #true
file "/var/log/sentinel/access.log"
}
}
}
limits {
max-header-size-bytes 8192
max-header-count 100
max-body-size-bytes 10485760
}
Setup
1. Deploy Redis
# Using Docker
# Or using Redis Cluster for HA
2. Start Sentinel
3. Start Backend Services
# Start API backends
&
Testing
Basic Rate Limiting
# Send 150 requests rapidly
for; do
done | |
Expected output shows 429 responses after limit exceeded:
100 200
50 429
API Key Rate Limiting
# Test with API key
for; do
done | |
Tiered Rate Limits
# Free tier (10 RPS limit)
# Premium tier (1000 RPS limit)
Check Rate Limit Headers
Response headers include:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1234567890
Monitor Metrics
|
Customizations
Memcached Backend
filter "memcached-rate-limit" {
type "rate-limit"
max-rps 100
burst 200
key "client-ip"
on-limit "reject"
backend "memcached"
memcached-url "memcache://memcached.internal:11211"
memcached-prefix "sentinel:ratelimit:"
memcached-pool-size 10
memcached-timeout-ms 50
memcached-fallback-local #true
}
Custom Rate Limit Keys
// By header value
filter "by-header" {
type "rate-limit"
key "header:X-Tenant-Id"
}
// By client IP (default)
filter "by-ip" {
type "rate-limit"
key "client-ip"
}
// By JWT claim (requires auth agent)
filter "by-user" {
type "rate-limit"
key "header:X-User-Id"
}
Enterprise Tier with Delay
filter "enterprise-tier-limit" {
type "rate-limit"
max-rps 10000
burst 20000
key "header:X-Org-Id"
on-limit "delay" // Slow down instead of reject
max-delay-ms 1000
backend "redis"
redis-url "redis://redis-cluster.internal:6379"
redis-prefix "sentinel:enterprise:"
redis-fallback-local #true
}
Next Steps
- HTTP Caching - Add response caching
- API Gateway - Complete API management
- Load Balancer - Advanced load balancing