Implementing Rate Limiting
1. Understanding Rate Limiting Need
| Threat | Mitigation |
|---|---|
| DoS (msg flood) | Per-connection msg/sec cap |
| Connection storm | Per-IP connect/sec cap |
| Slowloris | Handshake timeout |
| Bandwidth abuse | Bytes/sec cap |
| Auth brute force | Login attempts/min |
2. Implementing Connection Rate Limiting
Example: Per-IP connect counter
const conn = new Map();
function allow(ip, max = 5, windowMs = 60000) {
const now = Date.now();
const arr = (conn.get(ip) ?? []).filter(t => now - t < windowMs);
arr.push(now);
conn.set(ip, arr);
return arr.length <= max;
}
3. Implementing Message Rate Limiting
| Window | Detail |
|---|---|
| Fixed | Reset every N sec |
| Sliding | Last N sec rolling |
| Token bucket | Burst + steady rate |
| Leaky bucket | Smooth output rate |
4. Using Token Bucket Algorithm
Example: Token bucket
class TokenBucket {
constructor(capacity, refillPerSec) {
this.capacity = capacity; this.tokens = capacity;
this.rate = refillPerSec; this.last = Date.now();
}
take(n = 1) {
const now = Date.now();
this.tokens = Math.min(this.capacity, this.tokens + (now - this.last) / 1000 * this.rate);
this.last = now;
if (this.tokens < n) return false;
this.tokens -= n; return true;
}
}
| Param | Effect |
|---|---|
| capacity | Max burst size |
| refill | Sustained rate |
5. Using Leaky Bucket Algorithm
| Aspect | Detail |
|---|---|
| Behavior | Constant drain rate |
| Burst | Limited to bucket size |
| Best for | Smoothing output to downstream |
| vs Token bucket | No burst above drain rate |
6. Implementing Sliding Window
Example: Sliding count
const hits = [];
function allow(limit = 100, windowMs = 60000) {
const now = Date.now();
while (hits.length && now - hits[0] > windowMs) hits.shift();
if (hits.length >= limit) return false;
hits.push(now); return true;
}
7. Storing Rate Limit State
| Store | Use |
|---|---|
| In-memory Map | Single node |
| Redis (INCR + TTL) | Cluster-wide |
| Redis sliding-log | Accurate sliding window |
| Sharded counters | Hot-key avoidance |
8. Handling Rate Limit Exceeded
Example: Reject with hint
ws.send(JSON.stringify({ "type":"err","code":429,"retryAfter":1000 }));
// or close on repeated abuse
ws.close(1008, "rate-limit");
| Strategy | When |
|---|---|
| Soft drop | Best-effort traffic |
| Send 429 | API-style request |
| Close 1008 | Sustained abuse |
| Block IP | Repeat offenders |
9. Implementing Per-User Limits
| Tier | Limit Example |
|---|---|
| Anonymous | 10 msg/min |
| Free user | 60 msg/min |
| Paid | 600 msg/min |
| Internal | Unlimited (still bounded) |
10. Monitoring Rate Limit Metrics
| Metric | Purpose |
|---|---|
ws_rate_limit_hits_total | Counter by reason |
ws_rate_limit_close_total | Forced closes |
| Top offenders | IP / userId |
| Alert | Sudden spikes |