Rate Limiting: Panduan Lengkap Token Bucket, Leaky Bucket, dan Queue Burst MikroTik
“Rate limiting terlihat sepele — 'batasi 100 per menit, selesai'. Tapi setiap keputusan di dalamnya adalah trade-off antara melindungi sistem dan merusak pengalaman pengguna. Berikut cara memilihnya berdasarkan perhitungan, bukan tebakan.”
Daftar Isi Artikel
1 Kenapa Rate Limiting Ada
Setiap sistem punya kapasitas terbatas: bandwidth uplink, koneksi database, jumlah request per detik yang sanggup diproses CPU. Rate limiting adalah mekanisme untuk memastikan konsumsi sumber daya itu tidak melebihi batas yang kita tetapkan.
Ada empat motivasi yang berbeda, dan membedakannya penting karena menentukan algoritma mana yang cocok:
Mencegah server tumbang karena lonjakan trafik. Yang penting di sini adalah batas atas absolut — tidak boleh ada lonjakan yang menembus.
Satu klien tidak boleh menghabiskan kapasitas yang jadi jatah semua orang. Ini kasus klasik RT/RW net: satu pelanggan yang menarik torrent 24 jam tidak boleh membuat 30 pelanggan lain lemot.
Kalau Anda memanggil API pihak ketiga yang ditagih per request, atau punya kuota FUP dari ISP, rate limiting adalah rem finansial yang menjaga pengeluaran.
Membatasi percobaan login, pendaftaran massal, atau pengiriman OTP untuk mempersulit serangan brute force, credential stuffing, dan spam bot.
2 Kosakata Dasar
Sebelum masuk algoritma, empat istilah ini harus jelas karena sering tertukar dalam percakapan sehari-hari maupun konfigurasi router dan backend server:
| Istilah | Arti & Definisi | Contoh Riil |
|---|---|---|
| Rate (r) | Laju rata-rata yang diizinkan dalam jangka panjang | 10 request/detik, 5 Mbps |
| Burst (b) | Jumlah maksimum yang boleh dikonsumsi sekaligus di atas rate normal | 50 request sekaligus, 20 Mbps (2 detik) |
| Quota | Total absolut dalam periode panjang | 500 GB/bulan, 10.000 request/hari |
| Window | Rentang waktu tempat hitungan direset | per detik, per menit, per jam |
3 Algoritma Rate Limiting
3.1 Fixed Window Counter
Cara paling sederhana. Bagi waktu menjadi jendela tetap (misalnya per menit), hitung request dalam jendela itu, tolak kalau melewati batas.
key = user_id + ":" + floor(now / 60)
count = INCR(key)
if count == 1: EXPIRE(key, 60)
if count > limit: REJECT
3.2 Sliding Window Log
Simpan timestamp setiap request. Saat request baru masuk, buang semua timestamp yang lebih tua dari window, lalu hitung sisanya.
ZREMRANGEBYSCORE key 0 (now - window)
count = ZCARD key
if count < limit: ZADD key now now
else: REJECT
3.3 Sliding Window Counter
Kompromi cerdas antara keduanya. Simpan counter untuk jendela saat ini dan jendela sebelumnya, lalu interpolasi secara linear berdasarkan seberapa jauh kita sudah masuk ke jendela sekarang:
estimasi = count_sekarang + count_sebelumnya × (1 − posisi_dalam_jendela)
Contoh: limit 100/menit. Jendela lalu ada 80 request, jendela sekarang 30 request, dan kita berada di detik ke-15 (25% jendela berjalan):
estimasi = 30 + 80 × (1 − 0,25) = 30 + 60 = 90 (90 < 100, diterima).
3.4 Leaky Bucket
Bayangkan ember berlubang di dasarnya. Request masuk ke ember (antrean), dan bocor keluar diproses dengan laju konstan. Kalau ember penuh, request baru langsung dibuang.
- Output Selalu Halus & Konstan: Berapa pun kacaunya pola lonjakan input, keluaran selalu teratur (cocok untuk traffic shaping uplink).
- Tanpa Burst Pada Output: Lonjakan input hanya diserap oleh antrean, lalu dikeluarkan perlahan. Bagi pengguna, ini dirasakan sebagai lonjakan latency/antrian, bukan penolakan.
3.5 Token Bucket
Ember diisi token secara terus-menerus dengan laju r token/detik, sampai batas maksimum kapasitas b token. Setiap request mengambil sejumlah token sesuai biayanya. Jika token kosong, request ditolak atau antri.
tokens = min(b, tokens + (now − last_refill) × r)
last_refill = now
if tokens >= cost:
tokens −= cost
ALLOW
else:
REJECT
Perhitungan Lazy: Tidak ada timer atau cron background yang mengisi token. Token dihitung seketika (lazily) saat request datang dari selisih timestamp. Cukup 2 nilai per pengguna (tokens dan last_refill).
4 Matematika Token Bucket
Di sinilah perhitungan matematis jadi penentu, karena hubungan antar parameter seringkali tidak intuitif.
4.1 Durasi Burst Maksimum (T_burst)
Jika bucket penuh (b token) dan klien mengirim dengan laju R yang lebih besar dari laju isi r:
Contoh: b = 100 token, r = 10 token/s. Klien menggembur di R = 50 req/s:
T_burst = 100 / (50 − 10) = 2,5 detik (125 request berhasil diproses).
4.2 Waktu Pemulihan (T_recovery)
Setelah bucket kosong, waktu yang dibutuhkan agar ember terisi penuh kembali ke level b:
Contoh: 100 / 10 = 10 detik. Artinya untuk burst penuh 2,5 detik, klien harus istirahat 10 detik agar kapasitas pulih 100%.
4.3 Menghitung Retry-After
Jika request ditolak karena token kurang, durasi klien harus menunggu sebelum mencoba kembali:
Nilai ini wajib dikirim di header HTTP agar klien tidak melakukan retry membabi buta.
4.4 Menentukan Kapasitas dari Kebutuhan
Jika pengguna butuh memuat 200 request sekaligus saat dashboard dibuka, dengan konsumsi jangka panjang 5 req/s:
40 detik terlalu lama? Naikkan r, namun konsekuensinya konsumsi bandwidth jangka panjang juga meningkat.
Eksperimenkan kapasitas ember (bucket-size) dan laju demand dengan grafik animasi interaktif di workspace ini.
5 Burst di Dunia Jaringan (MikroTik RouterOS)
Implementasi burst di MikroTik berbeda dari token bucket murni, dan ini sumber kebingungan yang sangat umum di kalangan teknisi jaringan dan ISP RT/RW net. MikroTik menggunakan empat parameter:
burst-time BUKAN durasi lamanya burst! RouterOS menghitung rata-rata pemakaian selama burst-time terakhir dengan membaginya menjadi 16 interval sampling. Begitu rata-rata melampaui burst-threshold, laju dipangkas seketika kembali ke max-limit.
Rumus Durasi Burst MikroTik Aktual:
Contoh Konkret Kasus RT/RW Net
RouterOS CLI/queue simple add name="pelanggan-01" target=192.168.10.5/32 \
max-limit=2M/2M \
burst-limit=8M/8M \
burst-threshold=1M/1M \
burst-time=16s/16s
Perhitungan: T_burst = (1 × 16) / 8 = 2 detik.
Pelanggan mendapat 8 Mbps selama 2 detik pertama — cukup untuk membuka halaman web portal berita atau streaming video awal terasa instan tanpa buffer — lalu kecepatan turun mulus ke 2 Mbps. Ini menciptakan pengalaman "internet kencang" tanpa membuat pipa uplink overload!
Lihat kurva switching interval sampling 16 slice dan salin script RouterOS langsung ke MikroTik Anda.
6 Rate Limiting Terdistribusi
Semua kalkulasi di atas mengasumsikan sistem satu proses (single instance). Saat aplikasi Anda diskalakan ke beberapa instance di balik load balancer, counter di memori lokal tidak saling tahu. Dengan 4 instance dan limit 100/menit, seorang pengguna bisa lolos hingga 400 req/menit.
Pendekatan 1: Counter Terpusat Atomik (Redis + Lua)
Operasi token bucket harus dilakukan secara atomik agar bebas dari race condition. Gunakan skrip Lua berikut:
-- KEYS[1] = kunci bucket
-- ARGV[1] = kapasitas (b)
-- ARGV[2] = laju isi (r, token/detik)
-- ARGV[3] = cost
-- ARGV[4] = waktu sekarang (detik)
-- ARGV[5] = TTL
local tokens = tonumber(redis.call("HGET", KEYS[1], "tokens")) or tonumber(ARGV[1])
local last = tonumber(redis.call("HGET", KEYS[1], "ts")) or tonumber(ARGV[4])
local delta = math.max(0, tonumber(ARGV[4]) - last)
tokens = math.min(tonumber(ARGV[1]), tokens + delta * tonumber(ARGV[2]))
if tokens < tonumber(ARGV[3]) then
return 0
end
tokens = tokens - tonumber(ARGV[3])
redis.call("HSET", KEYS[1], "tokens", tokens, "ts", ARGV[4])
redis.call("EXPIRE", KEYS[1], ARGV[5])
return 1
Pendekatan 2: Kuota Terbagi
Bagi limit dengan jumlah instance (misal 4 instance = 25/menit tiap node). Sangat cepat dan tanpa koordinasi jaringan, namun tidak adil jika load balancer tidak membagi trafik secara merata.
Pendekatan 3: Hibrida (Hybrid)
Tiap instance menyimpan counter lokal di memori dan menyinkronkan batch ke Redis secara periodik (misal tiap 100 ms). Kompromi terbaik antara akurasi dan latensi pada arsitektur skala masif.
7 Berkomunikasi dengan Klien
Rate limiting yang baik tidak berjalan diam-diam. Kirimkan informasi kuota melalui standar header HTTP yang jelas:
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 47
Retry-After: 12
Klien: Exponential Backoff dengan Jitter
Di sisi aplikasi klien, gunakan algoritma backoff dengan variasi acak (jitter) untuk menghindari bencana Thundering Herd:
delay = min(max_delay, base × 2^percobaan) × (0.5 + random() × 0.5)
Tanpa randomisasi jitter, ribuan klien yang ditolak bersamaan akan mencoba ulang serempak pada detik ke-12 — menciptakan gelombang badai trafik berulang.
8 Kesalahan yang Sering Terjadi
Ratusan pengguna kantor atau operator seluler berbagi 1 IP publik (NAT/CGNAT). 1 user berat bisa memblokir seisi kantor. Gunakan kombinasi token/API-key untuk user login.
Query laporan analitik berat yang memakan 3 detik CPU tidak boleh berbiaya sama dengan endpoint cek saldo dari cache Redis. Terapkan cost berbeda.
Endpoint ekspor laporan PDF mungkin jarang dipanggil. Tapi jika ada yang memicu 100 ekspor paralel, CPU server 100% hang seketika.
Lonjakan status 429 adalah alarm: bisa jadi ada bug di aplikasi Android/web klien, serangan DDoS, atau limit Anda terlalu mencekik pengguna normal.
9 Memilih Parameter dari Data, Bukan Tebakan
Jangan menetapkan angka rate limit hanya dari perasaan atau intuisi. Ikuti 5 tahapan terukur ini:
r di sekitar P99 pemakaian normal.b sedikit di atas lonjakan tersebut.b / r. Jika waktu recovery terlalu panjang dan user sering butuh burst berturut-turut, tingkatkan r.10 Penutup & Kesimpulan
Rate limiting terlihat sepele, tapi setiap keputusan di dalamnya adalah trade-off antara perlindungan sistem dan kenyamanan pengalaman pengguna. Token bucket menang dalam popularitas karena ia satu-satunya algoritma yang membiarkan Anda mengatur kedua sisi itu secara terpisah dan eksplisit.
Praktisi Rekayasa Perangkat Lunak, Arsitektur Backend, & Jaringan Telekomunikasi. Panduan ini dirancang untuk menjembatani teori matematis traffic shaping dengan praktik lapangan pada router MikroTik dan API modern.