Rate limiting - A Probabilistic Approach
Rate limiting at Scale

The Simple Explanation
Imagine you're managing a very popular restaurant. You need to know two things:
How many different people visited today?
How many times did each person order food?
There two clever tools: HyperLogLog (HLL) and Count-Min Sketch.
HyperLogLog (HLL) - The Unique Visitor Counter
Think of HLL like a magical guest book that:
Only needs a tiny amount of space (1.5KB)
Can estimate millions of unique visitors
Might be off by 2% (which is totally fine!)
Count-Min Sketch - The Smart Traffic Counter
This is like having multiple security cameras counting how often each person comes in:
Each camera counts a bit differently
By combining all cameras' counts, we get a good estimate
Catches people who are visiting too frequently
The Technical Deep-Dive
Now let's look under the hood at how these systems actually work.
HyperLogLog Implementation
class HyperLogLog {
constructor(precision = 14) {
this.precision = precision;
this.m = 1 << precision; // Number of registers
this.registers = new Array(this.m).fill(0);
}
add(element) {
const hash = this.hashFunction(element);
const bucket = hash & (this.m - 1); // Determine register
const w = hash >>> this.precision;
this.registers[bucket] = Math.max(
this.registers[bucket],
this.leadingZeros(w) + 1
);
}
estimate() {
// Harmonic mean calculation for cardinality estimation
const harmonicMean = this.registers.reduce((sum, val) =>
sum + Math.pow(2, -val), 0);
return (this.m * this.m) / harmonicMean;
}
}
Count-Min Sketch Technical Details
class CountMinSketch {
constructor(width, depth) {
this.width = width;
this.depth = depth;
this.table = Array.from(
{ length: depth },
() => new Array(width).fill(0)
);
this.hashFunctions = this.generateHashFunctions();
}
add(item, count = 1) {
this.hashFunctions.forEach((hashFunc, i) => {
const j = hashFunc(item) % this.width;
this.table[i][j] += count;
});
}
estimate(item) {
return Math.min(
...this.hashFunctions.map((hashFunc, i) =>
this.table[i][hashFunc(item) % this.width]
)
);
}
}
Real-World Implementation at Scale
Key Technical Considerations
Memory Efficiency: Both algorithms use constant memory regardless of traffic volume
Error Bounds: HLL provides ±2% error rate, Count-Min Sketch error is configurable
Distributed System: Uses Redis CRDTs for counter synchronization across edge nodes
Performance: O(1) time complexity for both updates and queries
By combining these probabilistic data structures, we can efficiently track and limit millions of requests per second, all while maintaining minimal memory usage and providing accurate rate limiting capabilities.
Real-World Use Cases
API Management: An API processing 10M requests per day uses CMS to identify abusive clients without tracking individual IPs.
E-commerce: HLL prevents coupon abuse by estimating unique users during flash sales.
Cybersecurity: The combination of both algorithms detects DDoS attacks with minimal memory overhead.
Comparison: Traditional vs. Probabilistic Approach
| Feature | Database Counters | HLL+CMS Approach |
| Memory Usage | O(n) | O(1) |
| Distributed Sync | Complex | CRDT-friendly |
| Error Margin | 0% | 1-2% |
| Throughput | 10k RPS | 1M+ RPS |
When To Avoid This Approach
Banking transaction systems requiring exact counts
Legal compliance scenarios needing 100% accuracy
Systems with burst-spike allowances
References:
https://redis.io/docs/latest/develop/data-types/probabilistic






