Yazılım Geliştirme

API Rate Limiting ve Throttling Stratejileri

Fatih Algül
25.03.2026 237 görüntülenme

API Rate Limiting Nedir ve Neden Gereklidir?

Modern yazılım mimarisinde API'ler, sistemler arası iletişimin temel yapı taşlarıdır. Ancak sınırsız erişime açık bir API, kısa sürede aşırı yüklenmeye, performans düşüşüne ve hatta hizmet kesintilerine yol açabilir. Rate limiting, belirli bir zaman diliminde bir istemcinin yapabileceği istek sayısını sınırlandırma mekanizmasıdır. Throttling ise isteklerin hızını kontrol altına alarak sisteme düzgün bir akış sağlamayı amaçlar.

Rate limiting uygulamanın başlıca nedenleri şunlardır:

  • DDoS ve brute-force saldırılarına karşı koruma: Kötü niyetli isteklerin sistemi çökertmesini engeller.
  • Kaynak adaleti: Tüm kullanıcıların API kaynaklarından eşit şekilde faydalanmasını sağlar.
  • Maliyet kontrolü: Özellikle bulut tabanlı altyapılarda gereksiz kaynak tüketimini önler.
  • Hizmet kalitesinin korunması: Yanıt sürelerinin kabul edilebilir düzeyde kalmasını garanti eder.

Temel Rate Limiting Algoritmaları

1. Fixed Window (Sabit Pencere)

En basit yöntemdir. Belirli bir zaman penceresi (örneğin 1 dakika) tanımlanır ve bu pencere içinde izin verilen maksimum istek sayısı belirlenir. Pencere sona erdiğinde sayaç sıfırlanır.

# Python ile basit Fixed Window implementasyonu
import time
from collections import defaultdict

class FixedWindowLimiter:
    def __init__(self, max_requests, window_seconds):
        self.max_requests = max_requests
        self.window_seconds = window_seconds
        self.requests = defaultdict(list)

    def is_allowed(self, client_id):
        now = time.time()
        window_start = now - self.window_seconds
        # Pencere dışındaki istekleri temizle
        self.requests[client_id] = [
            t for t in self.requests[client_id] if t > window_start
        ]
        if len(self.requests[client_id]) < self.max_requests:
            self.requests[client_id].append(now)
            return True
        return False

limiter = FixedWindowLimiter(max_requests=100, window_seconds=60)

Dezavantajı: Pencere sınırında yoğunlaşma (burst) sorunu yaşanabilir. Örneğin, 59. saniyede 100 ve 61. saniyede 100 istek gelirse, 2 saniyelik dilimde 200 istek işlenmiş olur.

2. Sliding Window Log (Kayan Pencere Günlüğü)

Her isteğin zaman damgası kaydedilir ve mevcut zamandan geriye doğru pencere boyutu kadar bakılarak istek sayısı hesaplanır. Fixed window'daki burst sorununu çözer ancak bellek kullanımı daha yüksektir.

3. Sliding Window Counter (Kayan Pencere Sayacı)

Fixed window ve sliding window log yaklaşımlarının hibrit versiyonudur. Önceki ve mevcut pencerenin ağırlıklı ortalamasını alarak daha hassas bir hesaplama yapar. Bellek açısından verimlidir.

4. Token Bucket (Jeton Kovası)

En yaygın kullanılan algoritmalardan biridir. Sabit bir hızda jetonlar kovaya eklenir, her istek bir jeton harcar. Kova doluyken yeni jeton eklenmez, kova boşken istekler reddedilir. Burst trafiğe belirli ölçüde izin verirken uzun vadede ortalama hızı kontrol altında tutar.

# Token Bucket implementasyonu
import time

class TokenBucket:
    def __init__(self, capacity, refill_rate):
        self.capacity = capacity        # Kova kapasitesi
        self.refill_rate = refill_rate  # Saniyede eklenen jeton
        self.tokens = capacity
        self.last_refill = time.time()

    def _refill(self):
        now = time.time()
        elapsed = now - self.last_refill
        new_tokens = elapsed * self.refill_rate
        self.tokens = min(self.capacity, self.tokens + new_tokens)
        self.last_refill = now

    def consume(self, tokens=1):
        self._refill()
        if self.tokens >= tokens:
            self.tokens -= tokens
            return True
        return False

# Saniyede 10 istek, burst için 50 kapasiteli kova
bucket = TokenBucket(capacity=50, refill_rate=10)

5. Leaky Bucket (Sızdıran Kova)

Token bucket'a benzer ancak istekleri sabit bir hızda işler. Gelen istekler bir kuyruğa eklenir ve kuyruktan sabit hızda çekilir. Kuyruk dolduğunda yeni istekler reddedilir. Çıkış trafiğinin düzgün olması gereken senaryolarda idealdir.

Dağıtık Sistemlerde Rate Limiting

Tek bir sunucu üzerinde rate limiting uygulamak görece basittir. Ancak birden fazla sunucu veya mikroservis mimarisi söz konusu olduğunda merkezi bir çözüm gerekir. Bu noktada Redis en popüler seçenektir.

# Redis ile dağıtık rate limiting (Sliding Window)
import redis
import time

r = redis.Redis(host='localhost', port=6379)

def is_rate_limited(client_id, max_requests=100, window=60):
    key = f"rate_limit:{client_id}"
    now = time.time()
    pipe = r.pipeline()
    pipe.zremrangebyscore(key, 0, now - window)  # Eski kayıtları sil
    pipe.zadd(key, {str(now): now})               # Yeni isteği ekle
    pipe.zcard(key)                                # Toplam sayıyı al
    pipe.expire(key, window)                       # TTL ayarla
    results = pipe.execute()
    return results[2] > max_requests

Redis'in MULTI/EXEC veya Lua scripting desteği sayesinde atomik işlemler yapılabilir. Bu, race condition sorunlarını ortadan kaldırır.

HTTP Başlıkları ile İstemci Bilgilendirme

İyi tasarlanmış bir rate limiting sistemi, istemcilere durumları hakkında bilgi verir. Standart HTTP başlıkları şunlardır:

  • X-RateLimit-Limit: Pencere başına izin verilen toplam istek sayısı
  • X-RateLimit-Remaining: Kalan istek hakkı
  • X-RateLimit-Reset: Sayacın sıfırlanacağı zaman (Unix timestamp)
  • Retry-After: 429 yanıtında, istemcinin tekrar denemeden önce beklemesi gereken süre (saniye)
# Express.js middleware örneği
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711612800
Retry-After: 45

{
  "error": "rate_limit_exceeded",
  "message": "Istek limiti asildi. Lutfen 45 saniye sonra tekrar deneyin."
}

Throttling Stratejileri

Throttling, rate limiting'den farklı olarak istekleri tamamen reddetmek yerine hızlarını kontrol eder:

  • Hard Throttling: Limit aşıldığında istek kesinlikle reddedilir.
  • Soft Throttling: Belirli bir yüzdeye kadar (ör. %10) limit aşımına izin verilir.
  • Elastic/Dynamic Throttling: Sunucu yüküne göre limitler dinamik olarak ayarlanır. Kaynak kullanımı düşükken daha fazla isteğe izin verilir.

Katmanlı Rate Limiting

Üretim ortamlarında tek bir limit yerine birden fazla katman uygulamak en iyi pratiktir:

  1. Global limit: Tüm API için saniyede maksimum 10.000 istek
  2. Kullanıcı bazlı limit: Her kullanıcı için dakikada 100 istek
  3. Endpoint bazlı limit: Kritik endpoint'ler için daha düşük limitler (ör. /auth/login için dakikada 5 istek)
  4. IP bazlı limit: Aynı IP adresinden gelen istekleri sınırlama

API Gateway Seviyesinde Uygulama

Popüler API gateway çözümleri yerleşik rate limiting desteği sunar:

  • NGINX: limit_req_zone ve limit_req direktifleri ile leaky bucket algoritması uygular.
  • Kong: Rate Limiting eklentisi ile Redis destekli dağıtık limitler sunar.
  • AWS API Gateway: Kullanım planları ve API anahtarları ile entegre throttling sağlar.
# NGINX rate limiting konfigürasyonu
http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }
    }
}

İstemci Tarafı: Rate Limit ile Başa Çıkma

API tüketicisi olarak rate limit'lerle doğru şekilde başa çıkmak da önemlidir. Exponential backoff stratejisi en yaygın yaklaşımdır:

import time
import random
import requests

def api_call_with_backoff(url, max_retries=5):
    for attempt in range(max_retries):
        response = requests.get(url)
        if response.status_code != 429:
            return response

        # Exponential backoff + jitter
        wait = (2 ** attempt) + random.uniform(0, 1)
        retry_after = response.headers.get('Retry-After')
        if retry_after:
            wait = max(wait, float(retry_after))

        print(f"Rate limited. {wait:.1f}s bekleniyor...")
        time.sleep(wait)

    raise Exception("Maksimum deneme sayisi asildi")

Jitter (rastgele gecikme) eklemek kritik öneme sahiptir. Aksi halde tüm istemciler aynı anda tekrar deneyerek thundering herd sorununa yol açar.

Sonuç ve En İyi Pratikler

  • Rate limiting stratejinizi API tasarımının başından itibaren planlayın; sonradan eklemeye çalışmak çok daha zordur.
  • İstemcilere her zaman anlamlı HTTP başlıkları ve hata mesajları döndürün.
  • Farklı kullanıcı tipleri için farklı limitler tanımlayın (free vs. premium planlar).
  • Rate limit metriklerini izleyin ve uyarılar kurun. Sürekli limit aşımı yaşayan kullanıcılar, API tasarımında iyileştirme fırsatına işaret edebilir.
  • Dağıtık ortamlarda Redis gibi merkezi bir depo kullanarak tutarlılığı sağlayın.
  • Algoritma seçiminde token bucket çoğu senaryo için iyi bir başlangıç noktasıdır; burst trafiğe izin verirken ortalama hızı kontrol altında tutar.
Yazar Hakkında
Fatih Algül
TechSoft Solutions
Proje mi var?

Yazılım, IoT veya otomasyon konularında destek almak ister misiniz?

İletişime Geç