API Rate Limiting: Cara Lindungi SaaS dari Abuse
Token bucket, sliding window, atau leaky bucket — kapan pakai apa, serta implementasi konkret pakai Redis untuk SaaS skala kecil-menengah.
Kenapa rate limiting wajib
Tanpa rate limit, satu klien dengan bug atau intent abuse bisa:
- Bikin DB overload — query 10x normal volume.
- Bikin biaya cloud melonjak — egress, compute, log storage.
- Bikin user lain “kena imbas” — server lambat untuk semua.
Untuk SaaS, rate limit bukan opsional. Default semua endpoint.
3 algoritma populer
1. Token Bucket
- User punya “bucket” dengan kapasitas N token. Refill dengan rate R per detik.
- Setiap request consume 1 token. Habis → 429.
- Cocok untuk: API umum, allow burst kecil sambil cap rata-rata.
2. Sliding Window
- Hitung request dalam window terakhir (mis. 60 detik). Kalau > limit → 429.
- Cocok untuk: anti-abuse strict, prediksi rate yang akurat.
- Kekurangan: butuh storage per request (timestamp).
3. Leaky Bucket
- Queue request, drain dengan rate konstan. Queue penuh → 429.
- Cocok untuk: smoothing burst (mis. webhook delivery).
Untuk SaaS standar, Token Bucket paling fleksibel.
Implementasi Redis (Token Bucket)
-- KEYS[1]: rate limit key
-- ARGV[1]: capacity (max tokens)
-- ARGV[2]: refill rate per sec
-- ARGV[3]: now (timestamp ms)
local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local last = redis.call("HMGET", KEYS[1], "tokens", "ts")
local tokens = tonumber(last[1]) or capacity
local ts = tonumber(last[2]) or now
local elapsed = (now - ts) / 1000
tokens = math.min(capacity, tokens + elapsed * rate)
if tokens < 1 then
redis.call("HMSET", KEYS[1], "tokens", tokens, "ts", now)
return 0 -- denied
else
tokens = tokens - 1
redis.call("HMSET", KEYS[1], "tokens", tokens, "ts", now)
redis.call("EXPIRE", KEYS[1], 60)
return 1 -- allowed
end
Run via EVAL — atomic, no race condition.
Tier-based rate limit (untuk SaaS multi-tier)
tiers:
free:
requests_per_min: 15
burst: 30
basic:
requests_per_min: 60
burst: 100
pro:
requests_per_min: 240
burst: 500
Saat request masuk → lookup tier user → ambil limit → enforce dengan token bucket.
Header response yang baik
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1736812800
Retry-After: 23
Klien bisa back-off dengan benar tanpa nebak.
Best practices
- Limit di edge (Cloudflare Workers, API gateway) — cegah request masuk app server.
- Limit per IP + per API key — keduanya. IP saja bisa di-bypass dengan rotating IP.
- Soft limit dulu (warning) sebelum hard limit (block) — beri user waktu untuk fix.
- Whitelist untuk internal cron/batch.
Konsultasi arsitektur SaaS untuk diskusi rate limiting + arsitektur lebih dalam.