API Rate Limiting ve Throttling Best Practices
API'lerinizi aşırı kullanımdan ve kötüye kullanımdan korumak, hem hizmet kalitesini hem de maliyetleri kontrol altında tutmanın temelidir. Rate limiting (hız sınırlama) ve throttling (trafik yavaşlatma), bu korumayı sağlayan iki tamamlayıcı stratejidir. Ancak ikisi arasındaki farkı doğru anlamak ve doğru araçları seçmek, çözümün başarısını belirler.
1. Rate Limiting vs. Throttling: Temel Fark
| Özellik | Rate Limiting | Throttling |
|---|---|---|
| Yaklaşım | Limit aşıldığında isteği reddeder (429) | İsteği yavaşlatır veya kuyruğa alır |
| Kullanım Amacı | Kötüye kullanımı ve saldırıları önleme | Geçici yük artışlarını yönetme |
| Kullanıcı Etkisi | Ani red (429 hatası) | Gecikmeli ama sonunda işlenir |
Pratik Kural: Rate limiting, "sınırı aşanı durdur" der; throttling ise "sınırı aşanı yavaşlat, ama kaybetme" der. Çoğu üretim sistemi ikisini birlikte kullanır: kötüye kullanımı engellemek için rate limiting, meşru trafik patlamalarını yönetmek için throttling .
2. Doğru Algoritmayı Seçin
Algoritma seçimi, API'nizin trafik desenine ve korumak istediğiniz kaynağa bağlıdır.
| Algoritma | Davranış | En Uygun Olduğu Yer |
|---|---|---|
| Token Bucket | Kontrollü patlamalara izin verir; token'lar sabit hızda yenilenir | Genel amaçlı API'ler, ani trafik artışları |
| Leaky Bucket | İstekleri sabit hızda işler; patlamaları kuyruğa alır | Katı downstream hız koruması gereken durumlar |
| Sliding Window | Zaman penceresini kaydırarak daha adil sınırlama sağlar | Adaletin kritik olduğu, yüksek trafikli senaryolar |
| Fixed Window | Basit sayaç; pencere sınırlarında patlama sorunu yaşar | Basit, düşük ölçekli iç API'ler |
Öneri: Çoğu modern API gateway'i varsayılan olarak token bucket kullanır; hem patlamalara izin verir hem de genel hızı kontrol eder .
3. ASP.NET Core'da Rate Limiting Middleware
ASP.NET Core, yerleşik Microsoft.AspNetCore.RateLimiting middleware'i ile rate limiting desteği sunar.
Temel Yapılandırma:
csharp
builder.Services.AddRateLimiter(options =>
{
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
options.OnRejected = async (context, cancellationToken) =>
{
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
context.HttpContext.Response.Headers.RetryAfter =
((long)Math.Ceiling(retryAfter.TotalSeconds)).ToString(NumberFormatInfo.InvariantInfo);
}
await context.HttpContext.Response.WriteAsync("Rate limit exceeded.", cancellationToken);
};
options.AddFixedWindowLimiter("fixed", opt =>
{
opt.PermitLimit = 100;
opt.Window = TimeSpan.FromMinutes(1);
opt.QueueLimit = 0; // Kuyruk yok; hemen reddet
});
});
app.UseRateLimiter();
Önemli Detaylar:
-
FixedWindowRateLimiter,Retry-Aftermetadata'sını bir sonraki pencere sınırına göre otomatik hesaplar; bunu yanıt başlığına kopyalamak doğru bekleme süresini verir . -
UseRateLimiter(), endpoint bazlı politikalar ([EnableRateLimiting]) kullanılıyorsaUseRouting()sonrasında çağrılmalıdır . -
Kuyruk kullanmak (
QueueLimit > 0), anlık reddetmek yerine istekleri kısa süre bekletip işleyebilir; ancak gecikmeyi artırır .
4. Katmanlı Politika Stratejisi
Tek bir global limit yerine, katmanlı politikalar kullanmak daha etkilidir :
-
Hesap/Kullanıcı Bazlı: Genel kota (ör. ayda 1.000 istek).
-
Endpoint Bazlı: Hassas endpoint'ler (
/login,/search, LLM çağrıları) için daha sıkı limitler. -
IP Bazlı: Kimlik doğrulanmamış istekler için IP başına sınır.
-
Eşzamanlılık (Concurrency): Aynı anda işlenen istek sayısını sınırlama (ör. veritabanı bağlantı havuzunu korumak için).
Örnek: GitHub, kimlik doğrulanmamış kullanıcılar için saatte 60 istek, kimlik doğrulanmış kullanıcılar için 5.000 istek gibi katmanlı limitler uygular .
5. İstemci Tarafında Doğru Davranış: Exponential Backoff
Rate limiting, istemci tarafında doğru yönetilmezse, geçici bir sınırlama kalıcı bir kesintiye dönüşebilir.
Kurallar:
-
Retry-Afterbaşlığına uyun: Sunucu ne zaman tekrar deneyeceğinizi söylüyorsa, o süreyi bekleyin . -
Exponential Backoff + Jitter kullanın:
Retry-Afteryoksa, her denemede bekleme süresini katlayarak artırın ve rastgele bir sapma ekleyin . -
Sonsuz retry yapmayın: Maksimum deneme sayısı belirleyin; aşıldığında hatayı kullanıcıya bildirin.
-
X-RateLimit-Remainingkontrol edin: Bir sonraki isteği göndermeden önce kalan kotayı kontrol edin .
6. Standart HTTP Başlıkları ve Durum Kodları
İstemcinin kendi kendini yönetebilmesi için yanıtlarda standart bilgiler dönün :
| Başlık | Açıklama |
|---|---|
429 Too Many Requests |
Rate limit aşıldığında dönülen durum kodu |
Retry-After |
İstemcinin ne kadar süre (saniye veya HTTP tarihi) bekleyeceği |
X-RateLimit-Limit |
Penceredeki toplam istek limiti |
X-RateLimit-Remaining |
Kalan istek sayısı |
X-RateLimit-Reset |
Kotanın sıfırlanacağı zaman |
Hata Mesajı Örneği:
❌ "Too many requests."
✅ "100 istek/dakika limitini aştınız. 60 saniye sonra tekrar deneyin."
7. İzleme ve Uyarı (Monitoring)
Rate limiting, "kur ve unut" değildir; sürekli izleme gerektirir :
-
429 oranını izleyin: Hedef, %1'in altında tutmaktır. Yüksekse, limitler çok sıkı veya istemciler hatalı davranıyor olabilir.
-
İstemci bazlı 429 dağılımını görün: Tek bir istemci anormal sayıda 429 alıyorsa, kötüye kullanım veya yanlış yapılandırma olabilir.
-
P95 gecikmeyi izleyin: Throttling kuyruğu gecikmeyi artırabilir; dengenin korunduğundan emin olun.
Sonuç
Rate limiting ve throttling, API'nizi kötüye kullanımdan korurken meşru trafiğe de saygı gösteren bir denge sanatıdır. Doğru algoritmayı (token bucket çoğu senaryo için iyi bir başlangıçtır), katmanlı politikaları, standart HTTP başlıklarını ve istemci tarafında exponential backoff'u bir arada kullanmak, hem güvenliği hem de kullanıcı deneyimini korur. ASP.NET Core'un yerleşik middleware'i, bu mekanizmaları uygulamayı kolaylaştırır. Unutmayın: İyi bir rate limiting, kullanıcıyı cezalandırmaz; kötüye kullanımı durdururken meşru trafiği yönlendirir.