Backend API geliştirirken hız sınırlandırma (rate limiting), sunucunuzu aşırı yüklenmeye ve kötüye kullanıma karşı koruyan kritik bir güvenlik önlemidir. Bu yazıda, Redis ve Express.js kullanarak nasıl ölçeklenebilir bir rate limiting sistemi kurabileceğinizi adım adım keşfedeceksiniz.
Neden Rate Limiting Kullanmalısınız?
Rate limiting, bir istemcinin belirli bir zaman diliminde API'nize kaç istek gönderebileceğini sınırlar. Bu sayede:
- DDoS saldırılarının etkisini azaltırsınız
- Sunucu kaynaklarını adil bir şekilde dağıtırsınız
- API anahtarlarının kötüye kullanılmasını engellersiniz
- Kullanıcı deneyimini iyileştirirsiniz (tüm istemciler eşit hizmet alır)
Özellikle ücretsiz tier sunan API'lerde, rate limiting abonelik katmanları arasında fark yaratmak için de kullanılır. Ayrıca, JWT kimlik doğrulama ile birlikte kullanıldığında güvenlik katmanınızı daha da sağlamlaştırabilirsiniz.
Redis Neden Tercih Edilmeli?
Rate limiting verileri geçici ve yüksek hızlı erişim gerektirir. Redis, bellek içi bir veri yapısı sunucusu olarak bu iş için idealdir:
- Saniyede milyonlarca işlem yapabilir
- TTL (Time-to-Live) desteği ile otomatik süre sonu
- Atomic işlemlerle yarış koşullarını önler
- Kolay kurulum ve popüler kütüphane desteği
Alternatif olarak veritabanı veya dosya sistemi kullanılabilir ancak Redis ölçeklenebilirlik ve performans açısından en iyisidir.
Redis ile IP Tabanlı Rate Limiting Adımları
Aşağıda Express.js üzerinde çalışan ve Redis kullanan bir middleware örneği gösterilmiştir. Bu middleware her IP için dakikada maksimum 10 isteğe izin verir.
1. Redis İstemcisini ve Middleware'i Oluşturun
Öncelikle `redis` ve `express-rate-limit` benzeri bir paket yerine doğrudan Redis komutları kullanalım:
const redis = require('redis');
const client = redis.createClient();
const rateLimitMiddleware = (req, res, next) => {
const ip = req.ip;
const key = `rate:${ip}`;
client.incr(key, (err, count) => {
if (err) return next(err);
if (count === 1) {
client.expire(key, 60); // İlk istekte 60 saniye TTL ayarla
}
if (count > 10) {
return res.status(429).json({
error: 'Çok fazla istek gönderdiniz. Lütfen bekleyin.',
retryAfter: 60
});
}
next();
});
};
Burada `INCR` atomik olarak sayacı artırır. İlk istekte TTL ayarlanır, ardından sayaç 10'u geçerse 429 Too Many Requests hatası döner. Daha karmaşık senaryolarda Redis'in `MULTI/EXEC` ya da Lua scriptleri kullanılabilir.
2. Middleware'i Express Uygulamasına Ekleme
const express = require('express');
const app = express();
app.use(rateLimitMiddleware);
app.get('/api/', (req, res) => {
res.json({ message: 'Hoş geldiniz!' });
});
app.listen(3000);
Artık tüm API rotalarınız için rate limiting geçerli olacaktır. İsterseniz belirli rotalara özel limit tanımlayabilirsiniz.
İleri Düzey Stratejiler
IP tabanlı limitleme yeterli olmayabilir. Örneğin, aynı NAT arkasındaki kullanıcılar aynı IP'yi paylaşabilir. Bu durumda:
- Kullanıcı bazlı limitleme: API anahtarı veya JWT token'sı ile limitleme yapın. REST API hata yönetimi ile birlikte doğru hata kodları döndürmeyi unutmayın.
- Sliding window: Sabit pencere yerine kayan pencere algoritması kullanarak daha adil sınırlandırma yapın.
- Redis Cluster: Yüksek trafikli sistemlerde birden fazla Redis düğümü kullanarak ölçeklenebilirliği artırın.
Sık Yapılan Hatalar ve Dikkat Edilmesi Gerekenler
- TTL yenileme hatırlatması: İlk istekte TTL atanmazsa sayaç süresiz kalır. Her istekte `EXPIRE` çağırmak Redis'e gereksiz yük bindirir; doğru yöntem yukarıdaki gibi ilk istekte TTL ayarlamaktır.
- Yanlış IP tespiti: Proxy veya load balancer arkasındaysanız `req.ip` yerine `X-Forwarded-For` başlığını kullanın. Aksi halde tüm istekler aynı IP (proxy) üzerinden gelmiş gibi görünür.
- Hata mesajlarını standartlaştırın: 429 yanıtında `retry-after` header'ı ekleyerek istemcinin ne kadar beklemesi gerektiğini belirtin. JSON hata formatınızı tutarlı hale getirin.
- Redis bağlantı hataları: Redis sunucusu düştüğünde uygulamanızın çökmemesi için fallback mekanizması (örneğin, limitlemeyi geçici olarak devre dışı bırakma) ekleyin.
Performans Karşılaştırması: Redis vs In-Memory
| Özellik | Redis | In-Memory (Node.js) |
|---|---|---|
| Veri kalıcılığı | İsteğe bağlı (RDB/AOF) | Uygulama yeniden başlatılınca kaybolur |
| Ölçeklenebilirlik | Çoklu işlem/instance arasında paylaşılabilir | Her instance ayrı sayar, toplam limit hatalı olur |
| Gecikme | < 1 ms (network çağrısı) | < 0.1 ms (bellek içi) |
| Karmaşıklık | Ekstra bağımlılık | Basit, harici servis yok |
Gördüğünüz gibi Redis, dağıtık sistemler için vazgeçilmezdir. Tek instance'da basit projeler için in-memory çözüm yeterli olabilir.
Sonuç
Rate limiting, API güvenliğinin olmazsa olmazıdır. Redis ile uygulandığında hem hızlı hem de ölçeklenebilir bir yapı elde edersiniz. Yukarıdaki adımları takip ederek projenize kolayca entegre edebilirsiniz. Unutmayın, limitleme stratejinizi kullanıcı ihtiyaçlarına göre esnek tutun ve hata durumlarında anlamlı yanıtlar verin.
Sık Sorulan Sorular
Rate limiting için Redis kullanmak zorunlu mu?
Hayır, Redis zorunlu değil; alternatif olarak bellek içi veri yapıları, dosya tabanlı sistemler veya PostgreSQL gibi veritabanları da kullanılabilir. Ancak Redis yüksek performansı ve otomatik süre sonu desteğiyle en ideal çözümlerden biridir.
IP bazlı rate limiting yanlış pozitiflere (false positive) neden olur mu?
Evet, özellikle aynı IP'yi paylaşan kullanıcılar (örneğin, bir ofis ağı) veya NAT arkasındaki mobil kullanıcılar için yanlış pozitifler oluşabilir. Bu durumu hafifletmek için kullanıcı bazlı (API anahtarı veya token) limitleme daha doğru olacaktır.
Rate limiting yanıtında hangi HTTP durum kodu kullanılmalı?
Standart olarak 429 Too Many Requests durum kodu kullanılır. Ayrıca yanıta 'Retry-After' başlığı ekleyerek istemcinin ne kadar beklemesi gerektiğini belirtmelisiniz.






