Rate Limiting APIs: Algorithmen und Implementierungen
Deine API wird angegriffen. Nicht von hochentwickelten Hackern, sondern von einem einfachen Skript, das deine Endpunkte tausende Male pro Sekunde bombardiert, Ressourcen verbraucht und den Dienst für legitime Nutzer verschlechtert. Ohne Rate Limiting kann ein einzelner fehlerhafter Client deine gesamte Anwendung lahmlegen. Dieser Leitfaden erklärt die Kernalgorithmen und zeigt praktische Implementierungen in Node.js und Nginx, um deine API zu schützen.
Warum Rate Limiting wichtig ist
Rate Limiting steuert, wie viele Anfragen ein Client in einem bestimmten Zeitfenster stellen kann. Es ist deine erste Verteidigungslinie gegen:
- Brute-Force-Angriffe auf Login- oder API-Key-Endpunkte
- Denial-of-Service (DoS) durch übermäßige Anfragen
- Ressourcenerschöpfung durch teure Operationen wie Datenbankabfragen oder Dateiverarbeitung
- Missbrauch von kostenlosen Tarifen durch Scraper oder Bots
Neben der Sicherheit gewährleistet Rate Limiting eine faire Nutzung und hilft dir, Geschäftsregeln durchzusetzen, wie z. B. gestaffelte Preismodelle.
Rate Limiting Algorithmen
Vier Algorithmen dominieren das API-Rate-Limiting. Jeder hat Kompromisse bei Genauigkeit, Speicherverbrauch und Burst-Handling.
1. Fixed Window
Zähle Anfragen in festen Zeitintervallen (z. B. 100 Anfragen pro Minute). Wenn das Fenster zurückgesetzt wird, wird der Zähler zurückgesetzt.
- Vorteile: Einfach, geringer Speicherbedarf (ein Zähler pro Client).
- Nachteile: Burst an Fenstergrenzen. Ein Client kann 100 Anfragen um 12:00:59 und weitere 100 um 12:01:00 senden, effektiv 200 Anfragen in zwei Sekunden.
2. Sliding Window
Verfolge Zeitstempel jeder Anfrage und zähle, wie viele in die letzten N Sekunden fallen. Dies glättet Bursts.
- Vorteile: Genaue, keine Grenzspitzen.
- Nachteile: Höherer Speicherverbrauch (Zeitstempel speichern) oder Verwende einen Sliding-Window-Zähler mit gewichtetem Durchschnitt.
3. Token Bucket
Ein Bucket enthält Token. Token werden mit einer festen Rate hinzugefügt. Jede Anfrage verbraucht einen Token. Wenn der Bucket leer ist, wird die Anfrage abgelehnt.
- Vorteile: Erlaubt Bursts bis zur Bucket-Größe, erzwingt dann die durchschnittliche Rate.
- Nachteile: Erfordert Speicherung der Token-Anzahl und der letzten Auffüllzeit pro Client.
4. Leaky Bucket
Anfragen gelangen in eine Warteschlange (Bucket) und werden mit konstanter Rate verarbeitet. Wenn die Warteschlange voll ist, werden Anfragen verworfen.
- Vorteile: Glättet den Verkehr auf eine konstante Rate, ideal zum Schutz nachgelagerter Dienste.
- Nachteile: Fügt Latenz hinzu; nicht geeignet für Echtzeit-APIs.
| Algorithmus | Burst-Handling | Speicher | Anwendungsfall |
|---|---|---|---|
| Fixed Window | Schlecht | Gering | Einfache APIs |
| Sliding Window | Gut | Mittel | Allgemeiner Zweck |
| Token Bucket | Ausgezeichnet | Mittel | APIs mit Burst-Toleranz |
| Leaky Bucket | Keine | Mittel | Verkehr glätten |
Implementierung von Rate Limiting in Node.js
Wir implementieren einen Token-Bucket-Rate-Limiter mit Express und Redis für verteilten Zustand. Redis ist unerlässlich, wenn du mehrere Serverinstanzen hast.
Schritt 1: Abhängigkeiten installieren
npm install express redis
Schritt 2: Rate-Limiter-Middleware erstellen
const redis = require('redis');
const client = redis.createClient();
async function tokenBucketLimiter(req, res, next) {
const key = `rate_limit:${req.ip}`;
const capacity = 10; // max tokens
const refillRate = 1; // tokens per second
const now = Date.now();
const data = await client.hGetAll(key);
let tokens = data.tokens ? parseFloat(data.tokens) : capacity;
let lastRefill = data.lastRefill ? parseInt(data.lastRefill) : now;
// Refill tokens based on elapsed time
const elapsed = (now - lastRefill) / 1000;
tokens = Math.min(capacity, tokens + elapsed * refillRate);
if (tokens < 1) {
return res.status(429).json({ error: 'Too many requests' });
}
tokens -= 1;
await client.hSet(key, {
tokens: tokens.toString(),
lastRefill: now.toString()
});
await client.expire(key, 60); // auto-cleanup
next();
}
app.use(tokenBucketLimiter);
Diese Middleware prüft und aktualisiert die Token-Anzahl atomar. Für die Produktion verwende Redis-Transaktionen oder Lua-Skripte, um Race Conditions zu vermeiden.
Implementierung von Rate Limiting in Nginx
Nginx bietet integriertes Rate Limiting mit dem limit_req-Modul. Es verwendet einen Leaky-Bucket-Algorithmus.
Schritt 1: Eine Rate-Limit-Zone definieren
Im http-Block von nginx.conf:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
Dies erstellt eine 10MB-Zone namens api, die 10 Anfragen pro Sekunde pro IP erlaubt.
Schritt 2: Das Limit anwenden
In deinem location-Block:
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://backend;
}
burst=20 erlaubt kurze Bursts von bis zu 20 Anfragen. nodelay verarbeitet Burst-Anfragen sofort, anstatt sie in die Warteschlange zu stellen.
Best Practices für API Rate Limiting
- Geeignete Statuscodes zurückgeben: Verwende
429 Too Many Requestsund füge denRetry-After-Header hinzu. - Clients korrekt identifizieren: Verwende API-Schlüssel oder Benutzer-IDs anstelle von IP-Adressen, wenn möglich, da IPs gemeinsam genutzt (NAT) oder gefälscht werden können.
- Zustand verteilen: Verwende Redis oder einen ähnlichen Speicher für Multi-Instanz-Bereitstellungen.
- Protokollieren und überwachen: Verfolge Rate-Limit-Treffer, um Angriffe zu erkennen und Schwellenwerte anzupassen. Tools wie der Nginx Log Analyzer können dir helfen, 429-Antworten zu analysieren und missbräuchliche IPs zu identifizieren.
- Limits kommunizieren: Dokumentiere Rate Limits in deiner API-Dokumentation und füge Header wie
X-RateLimit-Limit,X-RateLimit-Remaininghinzu.
FAQ
Was ist der Unterschied zwischen Rate Limiting und Throttling?
Rate Limiting blockiert Anfragen über einem Schwellenwert, während Throttling sie verlangsamt (z. B. durch Warteschlangen oder Verzögerungen). Rate Limiting ist binär; Throttling ist graduell.
Welchen Rate-Limiting-Algorithmus sollte ich verwenden?
Für die meisten APIs bietet Token Bucket eine gute Balance: Es erlaubt Bursts, erzwingt aber eine durchschnittliche Rate. Wenn du eine strikte Glättung benötigst, verwende Leaky Bucket. Für Einfachheit funktioniert Fixed Window für APIs mit geringem Verkehr.
Wie handhabe ich Rate Limiting für authentifizierte vs. anonyme Benutzer?
Wende strengere Limits auf anonyme Benutzer an (z. B. nach IP) und großzügigere Limits auf authentifizierte Benutzer (z. B. nach API-Schlüssel). Du kannst auch gestaffelte Limits basierend auf Abonnementplänen implementieren.
Bereit, deinen API-Verkehr zu analysieren? Verwende unseren Nginx Log Analyzer, um Protokolle zu parsen, Rate-Limit-Verstöße zu erkennen und deine Schwellenwerte zu optimieren.