Mövzunu Açan #1
Giriş ve bağlam
Bir uygulamada kullanıcı başına veya hesap başına yapılabilecek API çağrılarını kontrol etmek, hizmetin stabilitesini ve maliyetini korumak için kritik. Ancak gelen trafiğin eşzamanlılığı ve veritabanı yükü, basit sayaçlar yerine daha güvenilir bir rate limit tasarımını gerektirir. Aşağıdaki tasarım çizgileri, veritabanı odaklı bir çözüm için somut adımlar sunar.

1. Veritabanı yapısı ve temel prensipler
  • Kullanıcıya özgü limit tablosu: user_id, window_start, window_end, allowed, used gibi alanlar kullanılır. Her kullanıcı için belirli bir zaman penceresinde ne kadar çağrı yapıldığını izleriz.
  • Zaman penceresi olarak kaydırmalı (sliding window) veya sabit pencere (fixed window) tercih edilebilir. Sabit pencere basittir ama bazı durumlarda dürtüsel yükleri artırabilir; kaydırmalı pencere daha pürüzsüz dağılım sağlar, ancak karmaşıktır.
  • Row-level locking yerine mertebeli ayrımlar: yüksek trafikte, bir user için ayrı bir parçaya (partition) yazma/okuma performansı için sade bir plan.


2. Basit sabit pencere örneği ve iyileştirme noktaları
  • Table: rate_limits(user_id, window_start TIMESTAMP, limit INT, used INT)
  • Yeni çağrı geldiğinde:
    • window_start hesapla (ör. 1 dk) ve mevcut satır mı yoksa yeni satır mı olduğunu belirle.
    • used artışını atomik şekilde yap: UPDATE ... SET used = used + 1 WHERE user_id = ? AND window_start = ? AND used < limit
    • ya da mevcut satır yoksa INSERT ... ON CONFLICT DO UPDATE ile başlat.
  • Veri temizliği: belirli aralıklarla eski pencereler temizlenir (TTL veya otomatik temizleme) ve toplam tablo boyutu kontrol altında tutulur.


3. Kaydırmalı (sliding) pencere için pratik bir yaklaşım
  • İlgili ölçüm: her istek için bir olay kaydı (timestamp) tutulur ve belirli bir süre içindeki olaylar sayılır.
  • İşlem akışı:
    • çağrı geldiğinde, belirli bir zaman aralığında (ör. son 1 dk) geçmiş olaylar temizlenir ve yeni olay eklenir.
    • bu yaklaşım için bazen bir tek timebucket ve bir complete_count güncellemesi kullanılır; Kafka veya Redis ile entegre edilirse performans iyileştirilir.
  • Avantaj: daha düzgün dağılım ve ani yükleri yumuşatma. Dezavantaj: veritabanında sürekli arama/temizlik gerektirir.


4. Dağıtık ve yüksek hacimli senaryolar için öneriler
  • Konsistentlik ve performans dengesi: eşzamanlı güncellemeler için optimistic locking veya upsert kullanımı.
  • Cache katmanı: Redis veya Memcached üzerinde sayacın kısa ömürlü kopyaları, veritabanı asıl kaynak olarak kullanılır. Cache hit oranı yüksekse veritabanı yükü düşer.
  • Partitioning ve sharding: kullanıcı bazında veya coğrafi bölgeye göre parçaleme, kontrollerin ölçeklenebilirliğini artırır.
  • Gecikme toleransı ve hatalar: limit aşıldığında 429 Too Many Requests gibi yanıtlar verilir; zaman uyumsuzluklar için mümkün olduğunca asenkron işleme kullanılır.


5. Gözden geçirme ve güvenlik dikkate alınan noktalar
  • Yanlı kısıtlamalar: kullanıcı/servis tipine göre farklı limitler.
  • İptal ve yeniden deneme etkisi: yeniden denemeler, gerçek limitleri bozabilir; backoff stratejileri uygulanabilir.
  • Audit ve gözlem: hangi kullanıcıların sık dinamik olarak sınırı zorladığına dair kayıtlar ve uyarılar.


Teşekkür ve katkı çağrısı
Bu tasarım üzerinde hangi senaryolarda hangi yaklaşımı tercih edersiniz? Sabit pencere mi yoksa kaydırmalı pencere mi daha güvenilir sonuç verir sizce? Redis ile entegre ederken hangi veritabanı tarafı tasarımını önceliklendirmek gerekir? Kendi projelerinizden karşılaştığınız performans/karmaşıklık deneyimlerinizi paylaşır mısınız?

Cavab vermək üçün daxil olmalısınız.

0 sitat seçildi