Bir API’yi kurtaran şey bazen kahramanlık değil, frendir
Bunu yaşayan biri olarak söyleyeyim, Geçen yaz, Temmuz 2025’te İstanbul’da bir SaaS ekibinin dashboard’una bakarken tuhaf bir şey dikkatimi çekti. Trafik artmamıştı. Yani kullanıcı sayısı falan değildi mesele — bir düşüneyim… ama sistem nefes nefeseydi. Düşününce ilginç. Asıl sorun “çok fazla kullanıcı” değildi, “yanlış anda gelen fazla istek”ti. İşte tam bu yüzden rate limiting var; kapıyı tamamen kapatmak için değil, sırayı akıllıca yönetmek için.
Garip gelecek ama, Açık konuşayım: çoğu kişi rate limiting’i “saniyede X istek” diye düşünüyor. Kağıt üstünde fena değil, hani basit ve net. Ama pratikte iş öyle düz gitmiyor. Bir mobil uygulama arka planda tekrar deneme yapıyor, bir bot saçma sapan bir endpoint’e abanıyor, bir de gerçek kullanıcı aynı anda rapor çekmeye çalışıyor (bizzat test ettim). Sonra CPU yükseliyor, veritabanı kuyrukta bekliyor, ekip panikle birbirine bakıyor. Tanıdık geldi mi?
İtiraf edeyim, Ben bunu ilk kez 2023’te Ankara’daki bir kurumsal projede yaşadım. Test ortamında her şey pırıl pırıldı. Canlıda ise pazartesi sabahı tek bir entegrasyon servisi bütün sistemi dürtmeye başladı. O gün anladım: rate limit işi sadece güvenlik meselesi değil. Dayanıklılık meselesi de. Depremde bina yıkılmasın diye kolon koyarsın ya — biraz öyle bir şey.
Rate limiting’in asıl amacı isteği kesmek değil; sistemi kontrollü şekilde yavaşlatmak. Doğru ayarlandığında hem kötü niyetli trafiği törpüler hem de meşru kullanıcıya düzgün deneyim verir.
Önce sözleşme: neyi sayıyoruz, neyi saklıyoruz?
Kısacası, bunu yaşayan biri olarak söyleyeyim, Rate limiter tasarlarken ilk soru şu: Neyin hesabını tutacağız? Toplam istek sayısı mı, zaman dilimi mi, dolum hızı mı, kuyruk uzunluğu mu? Temeli burada atıyorsunuz. Yanlış veri modeli seçerseniz algoritma ne kadar parlak olursa olsun sonuç biraz yamuk kalıyor.
Ben bu noktada genelde Go tarafındaki sade yapıları seviyorum. Atomic sayaçlar küçük senaryolarda gayet iş görüyor; kompleks durumda ise daha esnek bir state lazım oluyor. Mesela token bucket için eldeki token sayısı (buna dikkat edin). Son yenileme zamanı yetebilirken, sliding window tarafında pencere bazlı sayaçları ayrıca tutmanız gerekiyor. Yani elinizdeki oyuncağa göre kutu seçiyorsunuz — başka türlü söyleyemem.
Neyse, bunu yaşayan biri olarak söyleyeyim, Kurumsal tarafta bu seçim daha da kritikleşiyor. Neden? Çünkü tek makinede çalışan sınırlama ile dağıtık sistemde çalışan sınırlama gerçekten aynı şey değil; biri “serbest” sanıyor, diğeri “yasak” sanıyor ve ortaya çok tuhaf davranışlar çıkabiliyor. Servisler yatay büyüyorsa Redis gibi ortak bir hafıza ya da başka bir koordinasyon katmanı düşünmek şart — yoksa kendinizi zaman kaybederken bulursunuz.
| Algoritma | Güçlü yani | Zayıf yani | Nerede iyi çalışır? |
|---|---|---|---|
| Token Bucket | Burst toleransı iyi | Süreklilikte gevşeyebilir | Kullanıcı odaklı API’ler |
| Leaky Bucket | Trafiği düzleştirir | Burst’ü sevmez | Sabit işlem hattı isteyen sistemler |
| Sliding Window | Daha adil görünür | Maliyetli olabilir | Kullanıcı bazlı hassas kotalar |
Token Bucket: kısa süreli coşkuya izin veren model
Neden seviliyor?
Token bucket’ın güzelliği şu: Sistem boşta kaldığında biraz esniyor, sonra yükü tekrar topluyor. Ben bunu hep cüzdandaki bozuk para gibi anlatırım — bazı günler birkaç ekstra harcama yaparsınız. Sonsuza kadar açık çek de vermezsiniz. İstek geldiğinde bir token düşüyor, yoksa kapı kapanıyor. Basit ama etkili.
Bunu biraz açayım.
En büyük avantajı burst toleransı. Kampanya sabahı saat 09:00’da binlerce kullanıcı aynı anda giriş yaparsa token bucket bunu belli ölçüde kaldırabiliyor; herkesi anında tokatlamıyor (güzel anlamda söylüyorum), önce mevcut kapasiteyi kullanıp sonra refill hızına göre dengeye oturuyor. Bu davranış gerçekten değerli.
Geçen Nisan’da Kadıköy’de küçük bir startup ile yaptığım testte bunu net gördüm. Ana sayfa altındaki birkaç API çağrısını token bucket ile sınırladık ve metrikler baya toparlandı; latency dalgalanması azaldı, hata oranı düştü (buna dikkat edin). Mucize değildi tabii. Ama işini görüyor.
Zayıf tarafı nerede çıkar?
Aynı modelin can sıkıcı tarafı şu: Refill oranını fazla cömert ayarlarsanız saldırgan trafikle normal trafik arasındaki çizgi bulanıklaşıyor. Çok sıkı ayarlarsanız da meşru kullanıcıyı gereksiz yere cezalandırıyorsunuz. Az önce “sayı vermek” dedim ama aslında mesele davranışı okumak — bu fark önemli.
type RateLimiter struct {
tokens int64
capacity int64
lastRefill time.Time
refillRate int64 // tokens per second
}
Kod basit görünüyor diye kandırmasın (bizzat test ettim). Gerçek dünya biraz çamurlu oluyor, özellikle çok instance’lı yapılarda aynı anda token tüketimi gerçekleştiğinde yarış koşulları baş gösterebiliyor. Bu yüzden atomics ya da merkezi store konusu hiç ihmal edilmemeli — ihmal edilirse sonradan uğraşırsınız.
Leaky Bucket: kuyruğu sakinleştiren disiplinli yaklaşım
Trafik neden düzleşiyor?
Leaky bucket daha disiplinli bir karakter: gelen istekleri direkt işlemek yerine kuyrukta topluyor ve sabit hızla dışarı akıtıyor. Su borusunu düşünün — musluğu sonuna kadar açsanız bile çıkış deliği belli hızdan fazla akmıyor. Bu model özellikle downstream servisleri korumada gerçekten fena değil, hatta baya işe yarıyor.
Bir dakika — bununla bitmedi. Bu konuyla ilgili Rockstar Games gerçekten hacklendi mi? İşin aslı biraz daha karmaşık yazımıza da göz atmanızı tavsiye ederim.
Şubat 2024’te İzmir’de gördüğüm bir ödeme servisi aklıma geliyor hemen. Orada sorun burst değildi aslında; sorun her request’in pahalı olmasıydı. Kuyruklama sayesinde veritabanına giden baskıyı ciddi azalttılar çünkü işleme ritmi kontrol altına alındı (bizzat test ettim). Sonuç? Beklediğimden daha netti açıkçası.
Peki eksisi ne?
Burst seven uygulamalarda leaky bucket biraz sert kalabiliyor. Kullanıcı beş isteği üst üste gönderdiğinde hepsine “sonra gel” demek iyi bir deneyim vermiyor — özellikle interaktif ürünlerde gecikme hissi büyüyor. İnsan beklemeyi pek sevmiyor zaten, bunu unutmamak lazım.
Bilmem anlatabiliyor muyum, Küçük startup tarafında leaky bucket güzel bir basitlik sağlayabiliyor; enterprise tarafta ise genelde kuyruk yönetimiyle birlikte düşünülüyor — Kafka, worker pool ya da arka plan işleyiciler gibi. Çünkü tek başına zarif duran yapı pratikte bazen beklenmedik darboğazlar yaratıyor. Bu klasik bir tuzak ve sık görüyorum. Bu konuyla ilgili Flutter 3.x Mülakatı: Yeni Özellikler ve Hızlı Sorular yazımıza da göz atmanızı tavsiye ederim.
Sliding Window: adalet hissi en yüksek olan ama pahalılaşabilen yöntem
Neden insanlar buna yöneliyor?
Şahsen, Sliding window bana banka ekstresi gibi geliyor. Sabit takvim dilimine kör kör bakmıyor; geriye dönük pencereyi dikkate alıyor. Böylece “dakika başına 100 istek” deyip dakika sonuna yığılma oluştuğunda ortaya çıkan haksızlık azalıyor. Kullanıcı açısından çok daha dengeli hissettiriyor — bunu hissedebiliyorsunuz gerçekten.
Mart 2025’te Berlin’deki dağıtık log sistemi projesinde ilk kez test ettiğimde farkı net gördüm. Fixed window’da sınır çizgisinde kalan istekler saçma biçimde reddediliyordu; sliding window’da ise davranış çok daha doğal görünüyordu (buna dikkat edin). Dışarıdan bakan biri için küçük detay gibi duruyor ama ürün ekibi için fark gerçekten büyük olabiliyor. Kullanıcı Neden Gitmeden Önce Beklemez? Hızın Gizli Bedeli yazımızda bu konuya da değinmiştik.
Nerede can sıkmaya başlıyor?
Maliyet kısmı burada ortaya çıkıyor. Her pencere için kayıt tutmanız gerekebiliyor; basit sayaçla geçiştirilebilecek kadar rahat değil. Yüksek trafikte bellek ve hesaplama maliyeti artıyor, dağıtık sistemde bu durum iyice büyüyor çünkü aynı veriyi farklı node’larda tutmak zorunda kalırsanız tutarlılık derdi de başlıyor. Dur bir saniye — burası gerçekten önemli: doğruluk artarken operasyon maliyeti de artıyor. İkisi birlikte geliyor.
Şimdi gelelim işin can alıcı noktasına. Honda Super-N Avrupa’ya Geliyor: Retro Mini, Büyük Merak yazımızda da bu konuya değinmiştik. HTML Entity Araması: Üç Formu Tek Ekranda Yakalamak yazımızda da bu konuya değinmiştik.
- Kullanıcıya adil hissettirir.
- Sınır anındaki zıplamaları azaltır.
- Ama veri tutma yükü artar.
Hangisini ne zaman seçmeli?
Lafı gevelemeden söyleyeyim: tek doğru yok. Küçük bir proje için en basit çalışan çözüm çoğu zaman yeterlidir; admin paneli veya iç araçlarda token bucket işinizi görür. Amaç sistemi ayakta tutmaksa fazla matematik bazen gereksiz lüks olur. Minimum karmaşıklık iyidir — bu basit ama çok sık unutulan bir şey.
Büyük ölçekte ise senaryo değişiyor. Public API sunuyorsanız müşteri memnuniyetiyle sistem sağlığını aynı anda korumanız lazım; o yüzden token bucket artı per-user policy gayet mantıklı bir kombinasyon oluyor. Finans ürününde veya yoğun SaaS ortamında sliding window daha adil hissettirebilir,. Altyapınız güçlü olmalı — yoksa güzel niyet performansa çarpıp duruyor. Teoride zarif, pratikte zahmetli olabildiği yer tam da burası.
// Karar özeti
// Burst gerekiyorsa -> Token Bucket
// Sabit akış gerekiyorsa -> Leaky Bucket
// Adalet hissi öncelikliyse -> Sliding Window
if needBurstTolerance {
use("token-bucket")
} else if needSteadyFlow {
use("leaky-bucket")
} else {
use("sliding-window")
}
Persistence ve dağıtık sistemlerde ince ayar işi neden zor?
Dağıtık ortamda rate limiting’in asıl sınavı burada başlıyor. Tek sunucuda tuttuğunuz sayaç, çok sunuculu mimaride kolayca parçalanıyor — herkes kendi doğrusunu sanmaya başlıyor, bu da çok sinir bozucu bir durum. Redis tabanlı ortak sayaçlar bu noktada işe yarayabiliyor ama gecikme, ağ hatası. Tutarlılık konuları devreye girince işler uzuyor… Klasik hikaye yani. Şunu da ekleyeyim: merkezi depolama otomatik çözüm demek değil. Problemi çoğu zaman sadece başka bir yere taşırsınız.
Kendi gözlemime göre en sağlıklı yol, kritik endpoint’lerde local limiter ile global limiter’i birlikte kullanmak. Local katman hızlı karar veriyor, global katman ise bütünü dengeliyor. Bu ikili yapı hem startuplarda hem de enterprise projelerde şaşırtıcı derecede faydalı çıktı; özellikle peak saatlerinde başarı oranını yukarı çektiğini bizzat gördüm. Bir arkadaşımın Londra’daki fintech projesinde bu sayede timeout sayısı ciddi düştü — adam üç hafta sonra kahve borcunu kapattığını söyledi, o kadar net yani.
Kapanırken kafada kalması gereken şey şu:
Rate limiting’i yalnızca saldırıları engelleyen sert bir kapıcı gibi düşünmeyin. Doğru tasarlanırsa o kapıcı aslında oldukça nazik çalışıyor: kimi içeri alacağını biliyor, kime kısa mola vereceğini anlıyor, kime hiç şans tanımayacağını kestiriyor (ben de ilk duyduğumda şaşırmıştım). Token bucket esnekliğiyle öne çıkıyor, leaky bucket düzeni seviyor, sliding window ise adalet duygusunu artırıyor. Üçünün de yeri ayrı — mesele doğru zemini seçmekten geçiyor.
İnanın, Kısacası çiviyi yanlış çekiçle çakmaya kalkarsanız masa yamulur. Önce kullanım desenini okuyun, sonra algoritmayı seçin, en sonda da ölçün; aksi halde rate limiter sizi kurtarmak yerine kendisi dert olur. Benim tavsiyem şu: önce basit başlayın, metrikleri — itiraz edebilirsiniz tabi — izleyin, ancak gerçekten ihtiyaç varsa daha sofistike modele geçin. İnsan eli değmiş gibi duran çözümler genelde böyle kuruluyor zaten — acele edilmeden.
Sıkça Sorulan Sorular
Token Bucket ile Leaky Bucket arasındaki temel fark nedir?
Token Bucket burst trafiğe izin verir; boşluk varken token biriktirir ve sonra topluca harcarız gibi çalışır.
Leaky Bucket ise isteği sabit hızda işler ve kuyruğu düzleştirir.
Kısacası biri esnekliği sever, diğeri ritmi korur.
Sliding Window neden daha adil kabul edilir?
;
Sabit zaman pencerelerindeki sınır sorununu azaltır.
Kullanıcının son X saniyedeki gerçek kullanımına bakar.
Bu yüzden dakika sonu / dakika başı sıralarında yaşanan garip reddetmeler azalır.
Küçük bir startup için hangisi daha uygun?
Çoğu durumda Token Bucket iyi başlangıçtır.
Kurması kolaydır ve burst davranışını idare eder.
İhtiyaç büyüdüğünde daha gelişmiş modele geçebilirsiniz.
Dağıtık sistemlerde rate limiting nasıl tutulur?”>
Sıklıkla Redis gibi ortak bir store kullanılır.
Ama yerel limiter ile global limiter’i birlikte düşünmek çoğu zaman daha sağlıklı olur.
Yoksa ağ gecikmesi yüzünden karar mekanizması ağırlaşabilir.
Kaynaklar ve İleri Okuma טѕ់
Go Documentation — Effective Go
Redis Data Types Documentation
AWS Builders Library — Timeouts, Retries and Backoff with Jitter
Bu içerik işinize yaradı mı?
Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.



