Back to Blog

Caching, Idempotency & Rate Limiting

February 15, 20264 min
CachingIdempotencyRate Limiting
Caching, Idempotency & Rate Limiting

Caching, Idempotency ve Rate Limiting

Bu bölümde üç kritik backend konseptini ele alıyoruz:

  • Caching: Performansı artırır
  • Idempotency: Tekrarlanan isteklerde veri tutarlılığını korur
  • Rate Limiting: Sistemi kötüye kullanıma ve aşırı yüke karşı korur

Bu üçü birlikte kullanıldığında hem hızlı hem güvenli hem de ölçeklenebilir API’ler elde edilir.


1) Caching

Caching Nedir?

Caching, sık erişilen verilerin daha hızlı erişilebilen bir katmanda (çoğunlukla RAM) geçici olarak saklanmasıdır.

Kullanıcı sayısı arttıkça her isteğin DB’ye gitmesi şu sonuçları doğurur:

  • Veritabanı yükü artar
  • Sorgu süreleri uzar
  • API response süreleri yükselir
  • Kullanıcı deneyimi kötüleşir

Caching bu yükü azaltarak sistemi rahatlatır.


Ne Zaman Cache Kullanılmamalı?

  • Nadir erişilen veriler (cache maliyeti, getiriden fazla olabilir)
  • Çok sık değişen veriler (stale veri riski artar)
  • Cache, tek doğru kaynak (source of truth) olmamalıdır

Temel kural: Cache “doğruluk” değil, “hız” içindir.


Cache Türleri

1. In-Memory Cache (Map, LRU)

Veri, uygulamayı çalıştıran instance’ın RAM’inde tutulur.

Avantajlar

  • Çok hızlı
  • Kurulumu kolay
  • Ek servis gerektirmez

Dezavantajlar

  • Restart ile silinir
  • RAM ile sınırlıdır
  • Multi-instance ortamda tutarsızlık yaratır

Sticky sessions bazı durumlarda yardımcı olabilir fakat kalıcı çözüm değildir.


2. Distributed Cache (Redis)

Redis, cache’i uygulama sunucularından bağımsız bir servis olarak sunar.

Özellikle:

  • Birden fazla instance
  • Load balancer
  • Horizontal scaling

olan sistemlerde Redis neredeyse zorunludur.

Akış

  1. İlk istekte DB’den okunur
  2. Redis’e yazılır
  3. Sonraki isteklerde Redis’ten okunur
  4. Bulunursa direkt client’a döner

Cache Metodolojileri

  • On-Demand (Lazy Loading): İlk istek geldiğinde cache’lenir (en yaygın)
  • Prepopulation: Uygulama açılırken cache doldurulur (sabit ve sık kullanılan veri)

Cache Ömrü (TTL)

  • Absolute TTL: Süre dolunca silinir
  • Sliding TTL: Erişildikçe süre uzar

Pratikte en dengeli yaklaşım: Absolute + Sliding birlikte kullanmaktır.


Redis ile İlgili Notlar

Redis RAM tabanlı olduğu için çok hızlıdır; ancak:

  • Primary database değildir
  • Kompleks sorgu yeteneği sınırlıdır
  • Transaction/rollback mantığı RDBMS gibi değildir

Persistence seçenekleri

  • RDB: Periyodik snapshot
  • AOF: Her değişiklik loglanır (daha güvenli, daha maliyetli)

Cache Stratejileri

Cache-Aside (En yaygın)

  1. Redis’e bak
  2. Yoksa DB’den oku
  3. Redis’e yaz
  4. Client’a döndür
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);

const data = await dbCall();
await redis.set(key, JSON.stringify(data), 'EX', 60);
return data;

Write-Through

Veri aynı anda DB’ye ve cache’e yazılır (tutarlılık daha iyi, yazma maliyeti daha yüksek).


Fail-safe Cache (Fall-through to DB)

Redis ulaşılamazsa sistem çökmez; istek DB’ye düşer.

Akış: Client → API → Redis → (yoksa) DB

Bu davranış caching sistemlerinde kritik bir dayanıklılık kuralıdır.


2) Idempotency

Idempotency Nedir?

Idempotency, aynı isteğin bir kez ya da birçok kez gönderilmesinin aynı sonucu üretmesi demektir.

Örnekler:

  • DELETE /products/10 tekrar edilse bile sonuç değişmez (idempotent)
  • POST /orders her seferinde yeni order üretir (idempotent değil)

Neden Önemlidir?

Gerçek dünyada tekrar istekler kaçınılmazdır:

  • Ağ kopması ve retry
  • Double click
  • Mobil uygulamalarda timeout / yeniden deneme

Idempotency yoksa:

  • Çift sipariş
  • Çift ödeme
  • Stok hatası
  • Gereksiz e-posta / bildirim

gibi kritik problemler oluşur.


Çözüm: Idempotency Key

  1. Client her request için benzersiz bir Idempotency-Key üretir (genelde UUID)
  2. Backend bu key’i kısa TTL ile saklar (çoğunlukla Redis)
  3. Aynı key tekrar gelirse işlem tekrarlanmaz, önceki sonuç döndürülür
if (await redis.exists(key)) {
  return cachedResponse;
}
const result = await processPayment();
await redis.set(key, JSON.stringify(result), "EX", 300);
return result;

3) Rate Limiting

Rate Limiting Nedir?

Rate limiting, bir kullanıcı/IP’nin belirli bir sürede kaç istek atabileceğini sınırlamaktır.

Amaçlar

  • Brute-force’u engellemek
  • DDoS etkisini azaltmak
  • Sunucu maliyetini ve yükü kontrol etmek

Yaygın Algoritmalar

  • Fixed Window: “Dakikada 100 istek” (sınırda yığılma olabilir)
  • Sliding Window: Daha hassas zaman kaydırmalı kontrol
  • Token Bucket: En esnek ve popüler yaklaşım (jeton tüket/yenile)

Uygulamada Redis, bu sayaçları hızlı tutmak için sıkça kullanılır.


Üçü Birlikte Nasıl Çalışır?

Para transferi gibi kritik bir endpoint düşünelim:

  • Rate Limiting: Kullanıcının saniyede çok sayıda transfer denemesini engeller
  • Idempotency: Aynı transfer isteği tekrar gelirse ikinci kez işlem yapmaz
  • Caching: Okuma ağırlıklı veriler (ör. hesap özeti) hızlı sunulur; işlem sonrası cache güncellenir veya temizlenir