System DesignMastery
--Distributed Systems — ডিস্ট্রিবিউটেড সিস্টেম

Rate Limiting & Throttling

Duration৩০-৪৫ মিনিট
LevelIntermediate
FocusResource Protection
001Why It Matters

Rate Limiting কেন শিখতে হবে?

আপনার API তে একজন user প্রতি second এ ১০,০০০ request পাঠাচ্ছে। হয় DDoS attack, নাহয় তার buggy code এ infinite loop। Server overload — অন্য সব users blocked।

Rate Limiting হলো সমাধান — একটা user বা client কতটা request করতে পারবেন সেটা restrict করুন। এটা ছাড়া কোনো production API চালানো উচিত না।

Rate Limiting vs Throttling

Rate Limiting: নির্দিষ্ট time window তে max request count। Limit exceed → reject।
Throttling: Request reject না করে slow করুন বা queue করুন — more graceful।

কেন দরকার? — ৪টা কারণ

SECURITY

Brute force attacks রোধ। Login এ ৫ বার fail → block। DDoS mitigation করুন।

BUSINESS

Free tier: ১০০ req/day। Paid: ১০,০০০ req/day। API monetization এর basis।

FAIRNESS

একজন user সব resources নিতে পারবেন না। সব users fair share পাবেন।

STABILITY

System overload prevent। Buggy client থেকে server protect। SLA maintain।

002Algorithms

৪টা Rate Limiting Algorithm

Algorithm Overview

Token Bucket

একটা bucket এ tokens। প্রতি request এ ১টা token consume। Constant rate এ refill। Bucket full হলে tokens overflow হয়।

✅ Burst traffic handle করতে পারে

❌ Implementation কিছুটা complex

Leaky Bucket

Queue এর মতো। Requests constant rate এ "leak" হয়। Queue full হলে reject। Output সবসময় smooth।

✅ Consistent output rate

❌ Burst requests drop হতে পারে

Fixed Window

Fixed time window (১ min) এ count। Window শেষে reset। সবচেয়ে simple algorithm।

✅ সহজ implement করা

❌ Window boundary তে ২x spike possible

Sliding Window

প্রতিটা request এর timestamp রাখুন। Window এর বাইরেরগুলো drop। যেকোনো moment এ last N minutes check।

✅ Most accurate, no boundary issue

❌ High memory — প্রতি request store

Token Bucket — সবচেয়ে Popular

Token Bucket কীভাবে কাজ করে

Rate: 10 tokens/sec, Capacity: 20। User ২ seconds idle থাকলে ২০ tokens জমে। একসাথে ২০ requests করতে পারবেন (burst)। এরপর rate limit শুরু। Token না থাকলে 429 Too Many Requests return করুন।

Fixed Window Boundary Problem

Limit: ১০ req/minute। User 12:00:59 তে ১০টা পাঠালো, তারপর 12:01:01 তে আরো ১০টা। মাত্র ২ seconds এ ২০ requests! Fixed Window এটা allow করে কারণ দুটো আলাদা window। Sliding Window এটা prevent করে।

003Distributed Rate Limiting

Multiple Servers এ কীভাবে করবেন?

Single server এ in-memory counter সহজ। কিন্তু ১০টা API server থাকলে? প্রতিটার আলাদা counter থাকলে user ১০x request করতে পারবেন। সমাধান: Shared Redis counter।

Architecture: Client → LB → API Servers → Redis

PROBLEM — Local Counter

API Server 1 এর counter: user→47। API Server 2 এর counter: user→52। সব মিলিয়ে ৯৯ requests, কিন্তু প্রতিটা server আলাদাভাবে limit enforce করছে। User ১০x request করতে পারছে!

SOLUTION — Redis Shared Counter

Redis এ একটাই counter: rate:user123 → 47। সব API servers এই একই counter INCR করে। Limit: 100/min। সব servers একই counter দেখে — consistent enforcement।

Redis INCR + EXPIRE — Atomic Operation

INCR rate_limit:user123:202401011430 — atomic, sub-millisecond।
প্রথমবার INCR করলেন key নেই → value 1 তৈরি হয়। তারপর EXPIRE দিয়ে TTL set করুন। Race condition নেই কারণ INCR atomic।
004Code Examples

Practical Code

Python: Token Bucket + FastAPI Middleware

rate_limiter.py
import time, threading
from collections import defaultdict
from fastapi import FastAPI, Request, HTTPException

class TokenBucket:
    def __init__(self, rate: float, capacity: int):
        self.rate = rate           # tokens/second
        self.capacity = capacity   # max tokens (burst size)
        self.tokens = capacity     # start full
        self.last_refill = time.monotonic()
        self.lock = threading.Lock()

    def consume(self) -> bool:
        with self.lock:
            now = time.monotonic()
            # Add new tokens based on elapsed time
            elapsed = now - self.last_refill
            self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
            self.last_refill = now

            if self.tokens >= 1:
                self.tokens -= 1
                return True   # allowed
            return False      # rate limited

app = FastAPI()

# প্রতি user/API-key এর জন্য আলাদা bucket
# Free: 5/sec, Paid: 50/sec
TIERS = {
    "free": {"rate": 5, "capacity": 10},
    "paid": {"rate": 50, "capacity": 100},
}
buckets = {}

@app.middleware("http")
async def rate_limit(request: Request, call_next):
    api_key = request.headers.get("X-API-Key", "anonymous")
    tier = "paid" if api_key.startswith("paid_") else "free"

    if api_key not in buckets:
        cfg = TIERS[tier]
        buckets[api_key] = TokenBucket(cfg["rate"], cfg["capacity"])

    bucket = buckets[api_key]
    if not bucket.consume():
        raise HTTPException(
            status_code=429,
            detail={"error": "Too Many Requests", "tier": tier},
            headers={"Retry-After": "1",
                     "X-RateLimit-Limit": str(TIERS[tier]["rate"]),
                     "X-RateLimit-Remaining": "0"}
        )

    response = await call_next(request)
    response.headers["X-RateLimit-Remaining"] = str(int(bucket.tokens))
    return response

@app.get("/api/data")
async def get_data():
    return {"data": "success"}

Node.js: Redis Sliding Window Rate Limiter

redis_rate_limiter.js
const Redis = require('ioredis');
const redis = new Redis();

async function isRateLimited(userId, limit = 100, windowMs = 60000) {
    const now = Date.now();
    const windowStart = now - windowMs;
    const key = `rl:${userId}`;

    // Atomic pipeline — all 4 ops run together
    const [[, count]] = await redis
        .pipeline()
        .zremrangebyscore(key, 0, windowStart)   // remove old
        .zadd(key, now, `${now}`)               // add current
        .zcard(key)                               // get count
        .pexpire(key, windowMs)                   // set TTL
        .exec()
        .then(r => r.slice(2, 3));

    return { limited: count > limit, remaining: Math.max(0, limit - count) };
}

// Express middleware
const rateLimit = (limit, windowMs) => async (req, res, next) => {
    const key = req.headers['x-user-id'] || req.ip;
    const { limited, remaining } = await isRateLimited(key, limit, windowMs);

    res.set('X-RateLimit-Limit', limit);
    res.set('X-RateLimit-Remaining', remaining);

    if (limited) return res.status(429).json({
        error: 'Too Many Requests',
        retry_after: Math.ceil(windowMs / 1000)
    });
    next();
};

// Different limits for different endpoints
app.use('/api/login', rateLimit(5, 300000));   // 5 per 5 min
app.use('/api/search', rateLimit(30, 60000));  // 30 per min
app.use('/api/', rateLimit(100, 60000));       // 100 per min
005Real World

Real World Rate Limits

API / ServiceLimitAlgorithm429 Response
GitHub API৬০ req/hr (unauth), ৫০০০ (auth)Fixed Window403 + X-RateLimit headers
Twitter API v2১৫ req/15 min (basic)Sliding Window429 + Retry-After
Stripe১০০ req/secToken Bucket429 + retry suggestion
OpenAIRPM + TPM (tier based)Token Bucket429 + error.type
AWS API Gateway১০,০০০ req/sec defaultToken Bucket429 ThrottlingException
Cloudflare WAFCustom rulesToken BucketBlock / Challenge / Log

Production Headers & Tools

STANDARD HEADERS

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1706000000
Retry-After: 30

PRODUCTION TOOLS

nginx: limit_req_zone module
Kong: Rate Limiting plugin
AWS WAF: Rate-based rules
Traefik: RateLimit middleware

006Interview Preparation

Common Interview Questions

Q1: "Design a Rate Limiter" — কীভাবে approach করবেন?

1) Requirements clarify: per user? per IP? per API key? 2) Single server নাকি distributed? 3) Algorithm: Token Bucket (versatile)। 4) Storage: Redis (atomic INCR) 5) Response: 429 + Retry-After + X-RateLimit headers। 6) Edge cases: distributed clocks, Redis failure।

Q2: Fixed Window এর boundary problem কী? কীভাবে solve করবেন?

Window শেষে ও শুরুতে burst possible। User ২ seconds এ ২x limit use করতে পারে। Solution: Sliding Window Log (exact timestamps) অথবা Sliding Window Counter (approximate but fast)।

Q3: Rate Limiting কোথায় implement করা উচিত?

Best: API Gateway বা Load Balancer এ — upstream এ। Backend services পর্যন্ত excess traffic পৌঁছায় না। Also: Per-service level এ different limits। Avoid: Client side (bypass করা যায়)।

Interview এ এটা বলুন

"আমি Token Bucket algorithm ব্যবহার করবো কারণ এটা burst traffic handle করতে পারে। Distributed system এ Redis INCR দিয়ে atomic shared counter রাখবো। API Gateway তে implement করবো যাতে backend সুরক্ষিত থাকে। 429 + Retry-After header সবসময় দেবো।"
007Nginx Rate Limiting

Nginx দিয়ে Rate Limiting Setup

Production এ সবচেয়ে common approach হলো Nginx এ rate limiting configure করা। limit_req_zone এবং limit_req directive ব্যবহার করে সহজেই endpoint-specific limits দেওয়া যায়।

nginx_rate_limit.conf
# Rate limit zones define করুন (http block এ)
http {
    # Zone 1: login endpoint — per IP, 5 req/5min
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/m;

    # Zone 2: API — per user (X-User-Id header), 100/min
    limit_req_zone $http_x_user_id zone=api:20m rate=100r/m;

    # Zone 3: search — 30/min per IP
    limit_req_zone $binary_remote_addr zone=search:10m rate=30r/m;

    server {
        listen 80;

        # Login: strict — 5 per 5min, no burst
        location /api/login {
            limit_req zone=login burst=5 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }

        # Search: moderate burst allowed
        location /api/search {
            limit_req zone=search burst=10;
            limit_req_status 429;
            proxy_pass http://backend;
        }

        # General API: 100/min, burst of 20
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_req_status 429;
            # Custom 429 response
            error_page 429 /rate_limit.json;
            proxy_pass http://backend;
        }

        location = /rate_limit.json {
            internal;
            default_type application/json;
            return 429 '{"error":"Too Many Requests","retry_after":60}';
        }
    }
}

Nginx Rate Limiting Tips

burst মানে temporary spike allow। burst=20 মানে extra ২০টা request queue এ রাখা যাবেন। nodelay মানে burst requests queue না করে immediately process করুন। Login এ burst কম রাখুন, general API তে বেশি রাখুন।

008Tiered API Limits

Tiered Rate Limiting — API Monetization

Real world API তে different users different limits পায়। Free, Basic, Premium — প্রতিটা tier এর আলাদা rate limit। এটাই API monetization এর মূল ভিত্তি।

TierRate LimitBurstPrice
Free১০০ req/day5 req burstবিনামূল্যে
Basic১০,০০০ req/day50 req burst$9/month
Premium১,০০,০০০ req/day200 req burst$99/month
EnterpriseUnlimitedCustomCustom pricing

Implementation Pattern

1) X-API-Key header থেকে tier identify করুন (JWT claim বা DB lookup)। 2) Redis key: rate_limit:{api_key} tier-specific limit apply। 3) Response headers এ remaining count ও reset time জানাও। Stripe, OpenAI, GitHub সবাই এই pattern follow করে।

009Lesson Summary

SUMMARY — আজকে যা শিখলাম

Conceptএক লাইনে
Rate LimitingTime window এ max request — reject exceed করলেন
Token BucketBurst allow — API তে সবচেয়ে popular
Leaky BucketConstant output — smooth traffic
Fixed WindowSimple কিন্তু boundary spike problem
Sliding WindowAccurate কিন্তু memory intensive
Redis INCRDistributed shared counter — atomic
429 + Retry-AfterStandard rate limit response
010Knowledge Check
011Assignments
012Practical Lab