A production-style rate limiting system using:
- Node.js + Express (backend)
- Redis + Lua (atomic logic)
- React + Vite (dashboard)
- k6 (load testing)
This project shows how real systems handle concurrent traffic safely across multiple servers.
- Sliding Window Counter algorithm
- Redis-based distributed state
- Lua scripting for atomicity (no race conditions)
- Middleware-based rate limiting
- Real-time dashboard (logs + status)
- k6 load testing setup
- Simulated request buttons (frontend)
sequenceDiagram
participant Client
participant Node API (PM2)
participant Redis
Client->>Node API (PM2): HTTP Request
Node API (PM2)->>Redis: Execute Lua Script (Current & Prev Keys)
Note over Redis: Atomic execution:<br/>1. Read counts<br/>2. Calculate weighted avg<br/>3. Increment
Redis-->>Node API (PM2): Return { allowed: 1/0, remaining }
alt Allowed
Node API (PM2)-->>Client: 200 OK (X-RateLimit Headers)
else Blocked
Node API (PM2)-->>Client: 429 Too Many Requests
end
pnpm installCreate .env:
PORT=3000
REDIS_URL=redis://localhost:6379
LIMIT=10
WINDOW_SIZE=10If installed locally:
redis-serverOr using Docker:
docker run -p 6379:6379 redispnpm run buildpnpm run prodOr dev mode:
pnpm run dev"scripts": {
"test": "k6 run dist/tests/k6-test.js",
"build": "tsc",
"dev": "nodemon dist/api.js",
"prod": "node dist/api.js",
"watch": "tsc -w"
}pnpm installpnpm run devOpen:
http://localhost:5173
- Live logs
- Allowed / Blocked requests
- Remaining quota
- Manual testing buttons:
- Single request
- Burst mode
- Gradual requests
sudo apt update
sudo apt install k6If not available:
sudo snap install k6pnpm run testThis executes:
k6 run dist/tests/k6-test.jsK6_WEB_DASHBOARD=true k6 run dist/tests/k6-test.jsOpen:
http://localhost:5665
We approximate a continuous sliding window using:
estimated = (prevCount * overlap) + currCount
Where:
overlap = 1 - (time_into_current_window / window_size)
Because we assume:
requests in previous window were uniformly distributed
Reality:
- requests can be bursty
- timing info is lost
Previous window:
10 requests all happened at end
System assumes:
spread evenly → incorrect weighting
- Fast
- Memory efficient
- Works in distributed systems
- Prevents burst attacks
- Approximation (not exact)
- Floating point precision issues
- Depends on Redis
- Slight timing inaccuracies
- Lua script runs atomically inside Redis
- No race conditions
- Multiple servers rely on Redis
- Network delays possible
Without Lua:
GET → CHECK → INCR race condition
With Lua:
ALL INSIDE REDIS atomic
- Manual frontend clicks
- Burst requests
- Gradual requests
- k6 concurrent load
Dashboard shows:
- Timestamp
- User/IP
- Remaining quota
- Allowed/Blocked status
Helps visualize limiter behavior in real-time
Why:
- monitoring should always be available
- needed during debugging/high load
/test-hit or specific endpoints
- Redis → shared state
- Lua → atomic execution
- Sliding window → smooth limiting
- k6 → load testing
- Dashboard → visibility
- Handles real-world concurrency
- Uses distributed system design
- Includes observability + testing
- Covers tradeoffs (not just implementation)