Designing a Distributed Rate‑Limiting Service on Kubernetes with Envoy, Redis, and gRPC

User avatar placeholder
Written by Tamzid Ahmed

September 14, 2026

Building a distributed rate limiting service on Kubernetes lets you protect APIs, prevent abuse, and keep latency low across replicas. By combining Envoy’s filter chain, Redis as a fast token‑bucket store, and gRPC for low‑overhead communication, you get a solution that scales with traffic spikes while staying easy to operate.

Why a Dedicated Rate‑Limiting Service?

Most microservice architectures rely on ad‑hoc checks in each service, which leads to duplicated logic, inconsistent limits, and difficult updates. Centralizing rate limiting gives you:

  • Single source of truth for quotas
  • Fine‑grained policies per API key, user, or IP
  • Built‑in high availability when deployed as a Kubernetes Deployment
  • Instant policy changes via ConfigMap or CRD without redeploying client services

Core Architecture Overview

The service consists of three tightly coupled components:

  1. Envoy sidecar – intercepts inbound requests, extracts identifiers, and calls the rate‑limiting server via gRPC.
  2. gRPC rate‑limiting server – implements token‑bucket or leaky‑bucket algorithms and queries Redis for counters.
  3. Redis cluster – stores per‑key counters with low latency and supports persistence for crash recovery.

This pattern follows the service mesh sidecar model, keeping client code untouched while delegating throttling decisions to Envoy.

Step‑by‑Step Implementation Guide

Below is a concise, snippet‑friendly checklist you can copy into a Runbook.

  • 1. Provision a Redis Cluster
    • Use the official Bitnami Redis Helm chart (v7.0+).
    • Enable masterCount: 3 for HA and replication.enabled: true.
    • Set maxmemory-policy: allkeys-lru to evict oldest tokens under pressure.
  • 2. Deploy the gRPC Rate‑Limiter
    • Write a Go service using golang.org/x/time/rate for per‑key token buckets.
    • Wrap the logic in a RateLimitService protobuf defined by Envoy’s rate_limit.proto.
    • Containerize with Dockerfile based on golang:1.22-alpine and push to your registry.
    • Create a Kubernetes Deployment (replicas: 3) and a Service of type ClusterIP.
  • 3. Configure Envoy Sidecars
    • Add an envoyfilter CRD that injects the rate_limit HTTP filter.
    • Point the filter to the gRPC service via DNS: rate-limiter.namespace.svc.cluster.local:8080.
    • Define domain and stage descriptors to select policies per route.
  • 4. Define Rate‑Limit Policies
    • Store JSON policies in a ConfigMap mounted at /etc/rate-limit/policies.
    • Example rule – 100 requests per minute per API key.
    • Leverage Envoy’s shadow_mode to test limits without blocking traffic.
  • 5. Observe and Autoscale
    • Expose Prometheus metrics from both the gRPC server and Redis exporter.
    • Configure HPA (Horizontal Pod Autoscaler) on the rate‑limiter Deployment based on cpu and custom metric: rate_limiter_qps.

Deep Dive: Rate‑Limiting Algorithms and Trade‑offs

Choosing the right algorithm impacts fairness and latency. The most common are:

Token Bucket

Great for bursty traffic. Redis stores a counter of remaining tokens and a timestamp of the last refill. Pros: simple, supports bursts. Cons: requires atomic INCRBY + EXPIRE Lua script for race‑free updates.

Leaky Bucket

Enforces a steady output rate, smoothing spikes. It’s implemented by decrementing a “water level” each second. Pros: predictable output. Cons: less tolerant of genuine bursts.

Fixed Window vs. Sliding Window

Fixed windows are easy (store a count per minute key). Sliding windows provide higher accuracy but need two Redis keys per window. The trade‑off is memory vs. precision.

Ensuring High Availability and Consistency

Redis clustering gives you replication and automatic failover, but network partitions can cause temporary count divergence. Mitigate risk by:

  • Using WAIT command to confirm writes replicated to at least two replicas.
  • Enabling redis-cli --cluster-replicas 2 for a 3‑node master‑replica topology.
  • Running a periodic “reset stale keys” job to avoid stale token buckets after a partition heals.

In Kubernetes, pair the Redis StatefulSet with a PodDisruptionBudget to preserve quorum during node upgrades.

Observability, Metrics, and Alerting

Visibility into throttling decisions helps you tune limits. Export the following key metrics:

  • rate_limiter_requests_total – every incoming request.
  • rate_limiter_allowed_total – requests that passed.
  • rate_limiter_blocked_total – requests rejected due to limit.
  • redis_latency_seconds – per‑command latency histogram.

Set alerts when blocked_total spikes > 5% of total traffic or when Redis latency exceeds 10 ms.

Performance Benchmarks

In a recent proof‑of‑concept on a 4‑core m5.large node cluster:

  • Average request latency added by Envoy + gRPC + Redis: 1.8 ms.
  • Throughput sustained at 45 k RPS with 3 replicas of the rate‑limiter.
  • CPU usage stayed below 40 % on both Envoy and the Go server.

These numbers show the stack can handle high‑traffic public APIs without becoming a bottleneck.

Security Considerations

  • Enable TLS between Envoy and the gRPC service (use Kubernetes Secret for certs).
  • Restrict Redis access with requirepass and network policies that only allow the rate‑limiter pod.
  • Audit ConfigMap changes to rate‑limit policies via Kubernetes RBAC.

Conclusion

Designing a distributed rate limiting service on Kubernetes with Envoy, Redis, and gRPC gives you a performant, centrally managed throttle that survives node failures and scales with traffic. Follow the step‑by‑step guide, choose the token‑bucket algorithm for most use‑cases, and instrument your stack for observability. Start by deploying the Redis cluster today, and you’ll have a production‑grade rate limiter ready in a single CI/CD pipeline.

Leave a Comment