Prompt dan Konteks yang Berlaku
Desain rate limiter untuk platform API multi-tenant: tenant gratis mendapatkan 100 permintaan per menit, tenant berbayar mendapatkan 10.000, dan platform berjalan di beberapa instance aplikasi serta region. Bandingkan algoritma dan jelaskan shared state, respons 429, degradasi kegagalan, dan verifikasi.
Ini cocok untuk wawancara backend, platform, dan desain sistem. Catatan wawancara publik menyajikan masalah pengkodean token-bucket per pengguna dengan pengisian ulang berbasis waktu; materi desain sistem memperlakukan rate limiting sebagai diskusi standar API multi-tenant. Keahlian intinya adalah shared state, kebijakan tenant, dan perlindungan trafik—bukan menghafal pengaturan salah satu penyedia cloud.
Apa yang Dievaluasi Pewawancara
- Apakah Anda memisahkan rata-rata rate, kapasitas burst, keadilan tenant, dan perlindungan global.
- Apakah Anda dapat menjelaskan batasan dan biaya dari token bucket, fixed window, dan sliding window.
- Apakah shared state diperbarui secara atomik di seluruh instance sementara hot key, partisi, dan clock ditangani.
- Apakah respons 429, petunjuk retry, degradasi, dan telemetri mencegah limiter menjadi single point of failure.
Pertanyaan Klarifikasi Sebelum Menjawab
- Apakah subjeknya berupa API key, tenant, pengguna, IP, atau kombinasinya? Bagaimana permintaan anonim dikelompokkan?
- Apakah kebijakannya berupa rata-rata rate, sliding window yang ketat, atau burst yang terkontrol? Apakah ada juga kuota harian?
- Apakah multi-region memerlukan penegakan global yang tepat, atau apakah sedikit overrun dapat ditoleransi demi ketersediaan?
- Apakah permintaan yang ditolak harus menerima 429 secara instan atau masuk ke antrean terbatas (bounded queue)? Apakah dependensi dapat mentoleransi burst sama sekali?
Kerangka Jawaban 30 Detik
Saya akan menempatkan perlindungan IP kasar dan unauthenticated di gateway, lalu menegakkan kebijakan sadar-tenant di application layer. Jika API mentoleransi burst singkat, saya akan mulai dengan token bucket. Setiap bucket tenant menyimpan token dan waktu pengisian ulang terakhir dalam shared state yang atomik. Permintaan yang melebihi batas menerima 429 dengan petunjuk retry yang dapat dihitung. Jika penghitungan global yang tepat tidak diperlukan, kuota regional dan pemantauan overrun global menukar sedikit presisi demi latensi; kegagalan penyimpanan menggunakan kebijakan fail-open atau fail-closed yang eksplisit beserta peringatan (alerts).
Pembahasan Mendalam Langkah-demi-Langkah
Tentukan Anggaran dan Keadilan
Seratus permintaan per menit adalah anggaran jangka panjang tenant gratis, dan 10.000 adalah anggaran tenant berbayar. Keduanya juga membutuhkan kapasitas burst yang independen; satu counter global tidak dapat mengekspresikan kedua kebijakan tersebut. Pelindung global harus membatasi agregat RPS sehingga satu tenant besar tidak dapat menghabiskan koneksi database. Kunci kebijakan harus mencakup ID tenant, aksi API, dan versi kebijakan agar endpoint yang tidak terkait tidak berbagi kuota secara tidak sengaja.
Pilih Algoritma
| Algoritma | Semantik utama | Biaya dan risiko | Kecocokan |
|---|---|---|---|
| Token bucket | Rata-rata rate terbatas dengan burst terkontrol | Dua nilai state; pengisian ulang dan konsumsi harus atomik | API yang berhadapan dengan pengguna yang mentoleransi burst singkat |
| Fixed window | Menghitung permintaan dalam periode tetap | Batas periode dapat mendekati dua kali lipat dari rate yang dikonfigurasi | Aturan sederhana di mana perkiraan dapat diterima |
| Sliding window log | Hitungan tepat di window aktif | Menyimpan timestamp; memori dan pembersihan berbiaya mahal | Populasi kecil yang membutuhkan presisi ketat |
| Sliding window counter | Estimasi berbobot dari window yang berdekatan | Perkiraan tetapi efisien memori; potensi error harus dinyatakan | Batas keadilan skala besar |
AWS API Gateway mendokumentasikan throttling token-bucket: token rate mengekspresikan trafik steady-state dan burst mengekspresikan kapasitas bucket. Ini dapat mengembalikan 429, tetapi batasannya adalah target best-effort dan bukan batas matematis absolut. Pisahkan maksud kebijakan dari jaminan platform.
Invarian Token-Bucket
Jumlah token selalu berada dalam [0, capacity]. Saat permintaan tiba, isi ulang sebesar waktu yang berlalu dikalikan laju pengisian ulang, batasi pada kapasitas maksimum, lalu periksa apakah ada setidaknya satu token; permintaan yang diizinkan mengonsumsi satu token. Urutan ini berarti periode idle hanya mengakumulasi hingga batas burst dan bukannya membuat kredit tanpa batas setelah downtime.
~~~text allow(key, now): state = atomicRead(key) elapsed = max(0, now - state.lastRefill) refilled = min(capacity, state.tokens + elapsed * rate) if refilled < 1: atomicWrite(key, refilled, now) return reject(429) atomicWrite(key, refilled - 1, now) return allow ~~~
Dalam produksi, pseudocode harus berjalan sebagai satu skrip Lua, transaksi, atau operasi compare-and-swap yang setara. Dua panggilan baca dan tulis independen dapat menjual token secara berlebih (oversell) di bawah konkurensi. Timestamp harus berasal dari sumber monotonik tepercaya; klien tidak boleh mengirimkannya.
Penempatan dan Shared State
Gateway memblokir banjir IP yang jelas dan volume yang tidak terautentikasi; application layer menerapkan kebijakan tenant, pengguna, atau endpoint. Jika setiap instance hanya menghitung dalam memori lokal, load balancing memungkinkan satu tenant menyebarkan panggilan ke seluruh instance dan menerima beberapa kuota. Redis bersama, atomic key-value store, atau database dengan penulisan bersyarat dapat menyimpan state; pilihan tergantung pada latensi, presisi, dan model kegagalan.
Pilihan multi-region bersifat eksplisit: satu penyimpanan global memberikan alokasi yang lebih tepat dengan konsekuensi latensi lintas-region; bucket regional independen berjalan cepat tetapi dapat overrun sesaat; alokasi regional ditambah pelindung global berada di antara keduanya. Tanyakan apakah presisi lebih penting daripada ketersediaan sebelum mengklaim batas ketat global.
Penolakan, Degradasi, dan Telemetri
Kembalikan 429 dengan header Retry-After atau sisa kuota. Klien harus menggunakan bounded backoff daripada langsung mencoba lagi ke dalam feedback loop. Jika penyimpanan limiter gagal, penulisan berisiko tinggi umumnya fail-closed atau masuk ke antrean terbatas; pembacaan berisiko rendah dapat fail-open sesaat, tetapi memerlukan circuit breaker lokal, masa kedaluwarsa, dan batas agregat. Pantau tingkat izin dan tolak, penggunaan kuota per tenant, latensi penyimpanan, hot key, error skrip, dan beban downstream sebenarnya secara terpisah.
Contoh Jawaban Berkualitas Tinggi
Saya akan menggunakan dua lapisan: gateway melindungi dari banjir IP dan unauthenticated, sementara aplikasi menegakkan kebijakan tenant dan endpoint. Tenant gratis dan berbayar memiliki nilai rate dan burst yang terpisah. Saya akan memilih token bucket secara default karena API biasanya dapat mentoleransi burst singkat sambil tetap menegakkan rata-rata jangka panjang. Setiap bucket menyimpan token dan waktu pengisian ulang terakhirnya, dan satu skrip atomik melakukan isi ulang, pemeriksaan, serta konsumsi dalam penyimpanan bersama.
Jika region tidak memerlukan hasil global yang tepat untuk setiap permintaan, saya akan mengalokasikan kuota regional dan menggunakan telemetri global untuk mendeteksi overrun yang tidak biasa. Jika pembayaran atau penyelesaian kuota harus ketat, saya akan menggunakan titik keputusan dengan konsistensi lebih kuat dan menerima latensinya. Permintaan yang melebihi batas menerima 429 dan panduan retry; kegagalan penyimpanan memilih fail-closed, fail-open singkat, atau antrean terbatas berdasarkan risiko endpoint. Saya kemudian akan melakukan uji beban pada kapasitas burst, batas window, keadilan tenant, pemulihan kegagalan, dan beban downstream—bukan hanya jumlah respons 429.
Kesalahan Umum
- “Gunakan Redis counter” → tidak ada semantik kebijakan atau atomisitas → tentukan state bucket, batas skrip, dan perilaku kegagalan.
- Satu kuota untuk setiap tenant → tenant besar membuat tenant kecil kelaparan → partisi kebijakan berdasarkan tenant dan endpoint, lalu tambahkan pelindung global.
- Memperlakukan fixed window sebagai batas per menit yang ketat → trafik batas window dapat mendekati dua kali lipat rate → nyatakan error dan pilih sliding atau token bucket jika diperlukan.
- Membuka akses sepenuhnya saat penyimpanan limiter gagal → dependensi akan tumbang lebih dulu → pilih degradasi terbatas berdasarkan risiko bisnis dan buat peringatan untuk itu.
- Menyuruh klien untuk segera mencoba lagi pada 429 → trafik yang ditolak menjadi beban tambahan → berikan panduan retry, jitter, dan batas maksimal.
Pertanyaan Lanjutan dan Jawaban
Bagaimana Anda mencegah satu tenant melipatgandakan kuota di 20 instance?
Tempatkan state bucket di penyimpanan bersama yang terlihat oleh setiap instance dan perbarui secara atomik di bawah kunci kebijakan tenant. Jika hanya counter lokal yang tersedia, sebut hasilnya sebagai perkiraan dan tambahkan batas di tingkat gateway; jangan mengklaim presisi global.
Bagaimana jika 100 permintaan per menit harus ditegakkan secara ketat di seluruh region?
Gunakan titik keputusan global dengan konsistensi lebih kuat atau lakukan serialisasi deduksi melalui home region milik tenant. Biayanya adalah latensi lintas-region dan ketersediaan yang lebih rendah selama kegagalan regional. Jika overrun singkat dapat diterima, gunakan kuota regional ditambah rekonsiliasi dan cantumkan toleransi error ke dalam SLO.
Bagaimana Anda mencegah limiter yang lambat memperlambat API?
Tetapkan batas waktu (timeout) yang ketat dan pasang circuit breaker di sekitar pemanggilan limiter. Pertahankan batas keamanan lokal jika terjadi pemadaman penyimpanan dan lakukan degradasi berdasarkan risiko endpoint. Lacak latensi limiter, timeout, dan kegagalan skrip secara independen dari tingkat keberhasilan bisnis.
Kapan Anda harus mengantrekan alih-alih mengembalikan 429?
Antrekan hanya jika pekerjaan bersifat asinkron, waktu tunggu sesuai dengan anggaran pengguna, dan dependensi memerlukan perataan beban (smoothing). Antrean harus dibatasi (bounded) dan menolak jika penuh. Pembacaan interaktif atau penantian tanpa batas biasanya harus mengembalikan 429 secara jujur.
Bagaimana Anda menguji kelemahan batas fixed-window?
Kirim satu burst tepat sebelum window berakhir dan satu lagi tepat setelah window dimulai, lalu hitung permintaan di setiap interval bergulir (rolling interval). Ulangi dengan pengisian ulang saat idle pada token-bucket, burst bucket penuh, dan konsumsi konkuren menggunakan clock yang terkontrol.