Rate limiting - A Probabilistic Approach

SedhuSedhu
3 min read

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!)

graph TD
    A["Visitors"] --> B["Magic Guest Book (HLL)"]
    B --> C["Approximate Count"]
    style B fill:#f9f,stroke:#333

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

graph LR
    A["Requests"] --> B["Multiple Counters"]
    B --> C["Counter 1"]
    B --> D["Counter 2"]
    B --> E["Counter 3"]
    C & D & E --> F["Final Count"]

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

graph TD
    A["Incoming Request"] --> B["Edge Node"]
    B --> C["HLL Counter"]
    B --> D["Count-Min Sketch"]
    C & D --> E["Redis Cluster"]
    E --> F["Rate Limit Decision"]
    style B fill:#96f,stroke:#333
    style E fill:#f96,stroke:#333

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

FeatureDatabase CountersHLL+CMS Approach
Memory UsageO(n)O(1)
Distributed SyncComplexCRDT-friendly
Error Margin0%1-2%
Throughput10k RPS1M+ 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

0
Subscribe to my newsletter

Read articles from Sedhu directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sedhu
Sedhu

FullStack / ETL Developer. Algo-Trader at NSE. Blockchain Enthusiast.