A distributed, configurable HTTP rate limiter built in Go using Redis and Lua, with asynchronous telemetry collection and ClickHouse-based analytics.
TelemetryGate is a production-oriented rate limiting service designed to protect APIs from excessive traffic while providing visibility into rate-limit decisions and system behavior.
The project focuses on building a high-performance rate limiter that can be deployed across multiple application instances while maintaining a shared rate-limit state through Redis.
A simple in-memory rate limiter works well for a single application instance, but becomes difficult to maintain when the application is horizontally scaled. Each application instance must share the same rate-limit state.
TelemetryGate addresses this by storing rate-limit state in Redis and using atomic Lua operations to safely update that state under concurrent traffic.
- Distributed rate limiting using Redis
- Atomic rate-limit operations using Lua scripts
- Configurable rate-limiting algorithms
- HTTP middleware integration
- Per-client rate limiting using configurable keys
200 OKresponses for allowed requests429 Too Many Requestsresponses for rejected requestsRetry-Afterand rate-limit headers- Asynchronous telemetry pipeline
- ClickHouse integration for telemetry analytics
- Docker Compose support
- Runtime CPU profiling using Go
pprof - Load testing using k6
- Graceful fallback when telemetry storage is unavailable
Redis provides low-latency shared state across multiple TelemetryGate instances.
Rate-limit state transitions are executed atomically inside Redis to prevent race conditions between concurrent requests.
Telemetry events are emitted asynchronously so ClickHouse availability or ingestion latency does not block the request path.
Rate-limit events are append-heavy and primarily queried through aggregations such as:
- top blocked clients
- requests per API
- rate-limit violations
- average request latency
- suspicious clients
ClickHouse's column-oriented storage and analytical query performance make it suitable for this workload.
Redis is part of the rate-limiting critical path. If rate-limit state cannot be evaluated, the service follows the configured failure policy rather than silently pretending that the request was successfully rate-limited.
Telemetry should not indefinitely block request processing. Events may be dropped according to the configured telemetry policy when the asynchronous buffer is saturated.
TelemetryGate is designed around an interface-based rate limiter so that different algorithms can be selected without changing the HTTP middleware.
Currently implemented algorithms:
- Fixed Window
- Sliding Window
- Token Bucket
- Leaky Bucket
The algorithm can be selected through configuration.
Example:
rateLimitConfig:
algorithm: "fixed_window"
burst: 7
limit: 5
window: 60
The primary performance goals are:
- Low request latency
- High throughput
- Atomic distributed rate limiting
- Minimal Redis round trips
- Non-blocking telemetry processing
- Predictable behavior under overload
k6 is used to evaluate TelemetryGate under different workloads. Test categories:
- Smoke Test
- Spike Test
- Stress Test
Following results were obtained during spike testing:
| Algorithm | p50 | p95 | p99 |
|---|---|---|---|
| Fixed Window | 2.25 ms | 4.20 ms | 14.94 ms |
| Sliding Window | 2.85 ms | 5.50 ms | 13.47 ms |
| Token Bucket | 2.75 ms | 5.88 ms | 15.64 ms |
| Leaky Bucket | 2.66 ms | 5.11 ms | 14.56 ms |
Under the tested local configuration, TelemetryGate sustained approximately 4.3K requests/sec during a rejection-heavy stress workload. CPU profiling showed that HTTP socket writes were a significant CPU consumer, indicating that response handling rather than Redis/Lua execution was a major bottleneck in this workload.
During the stress test, the CPU profile showed a significant amount of time associated with HTTP socket writes. Representative profile:
This indicates that under the rejection-heavy benchmark, HTTP response/socket handling was a significant CPU consumer. This was an important performance-engineering finding because it prevented prematurely optimizing Redis or the rate-limiting algorithm without evidence.
Performance numbers depend on:
- CPU
- Docker configuration
- Redis placement
- Network latency
- Request/response size
- k6 configuration
- Rate-limit configuration
Therefore, these numbers should be treated as local benchmark results, not production capacity guarantees.
This project was built to explore several backend and distributed-systems concepts:
-
Distributed state - Application-local counters cannot provide consistent rate limiting across multiple instances.
-
Atomic operations - Redis Lua scripts allow multiple state changes to be executed atomically.
-
Middleware design - Rate limiting can be implemented independently of application business logic through HTTP middleware.
-
Extensible architecture - Using interfaces, factories, and registries makes it possible to introduce new algorithms without changing middleware code.
-
Async telemetry - Analytics should not unnecessarily increase the latency of the critical request path.
-
Performance profiling - Load testing tells you that a system is slow while profiling helps determine why.
| Component | Technology |
|---|---|
| Language | Go |
| HTTP | Go net/http |
| Rate Limiting | Fixed Window, Sliding window, Token Bucket , Leaky Bucket |
| Distributed State | Redis |
| Atomicity | Redis Lua |
| Analytics | ClickHouse |
| Load Testing | k6 |
| Profiling | Go pprof |
| Containerization | Docker / Docker Compose |
| Configuration | YAML |
Start Redis:
docker compose up -d redis
Run the application:
go run cmd/TelemetryGate/main.go --config config/local.yaml
Check the service:
curl http://localhost:8082/app/v1/data
This project is intended for educational purposes.


