API-Ratenbegrenzung erklärt: Algorithmen, Header und Behandlung von 429-Fehlern

  1. Startseite
  2. Blog
  3. Softwareentwicklung

Softwareentwicklung

API-Ratenbegrenzung erklärt: Algorithmen, Header und Behandlung von 429-Fehlern

Ratenbegrenzungen schützen APIs vor Überlastung und Missbrauch. Erfahren Sie mithilfe einer von uns durchgeführten Simulation, wie sich die Hauptalgorithmen verhalten, wie eine gute 429-Antwort aussieht und wie Kunden zurücktreten sollten.

8 Min. Lesezeit
API-Ratenbegrenzung erklärt: Algorithmen, Header und Umgang mit 429-Fehlern

Das Wichtigste

  • Die Ratenbegrenzung begrenzt die Anzahl der Anfragen, die ein Kunde in einem bestimmten Zeitraum stellen kann.
  • Der Token-Bucket ermöglicht kurze Bursts und erzwingt gleichzeitig eine durchschnittliche Rate.
  • Ein einfaches festes Fenster kann die doppelte Grenze an einer Fenstergrenze durchlassen.
  • Geben Sie 429 Too Many Requests mit einem Retry-After-Header zurück und veranlassen Sie die Clients, sich mit Jitter zurückzuziehen.

Ein fehlerhaftes Skript ruft Ihre API in einer engen Schleife auf. Ohne Einschränkungen kann es den Dienst für jeden anderen Benutzer verlangsamen oder eine hohe Cloud-Rechnung verursachen. API-Ratenbegrenzung ist die Leitplanke, die einen einzelnen Kunden davon abhält, mehr als seinen gerechten Anteil zu nehmen.

Um zu zeigen, wie sich die gängigen Algorithmen verhalten, haben wir kleine Python-Versionen geschrieben und ihnen simulierte Anforderungszeiten zugeführt. Die folgenden Ausgaben stammen aus diesem Lauf. Sie lehren Modelle, keinen Produktionscode, und echte Gateways verfügen über mehr Funktionen.

Was ist eine Ratenbegrenzung?

Bei der Ratenbegrenzung werden Anfragen pro Kunde gezählt und Anfragen über einem vereinbarten Grenzwert, z. B. 100 Anfragen pro Minute, abgelehnt oder verzögert. Eine verwandte Idee, Drosselung, bedeutet oft, Anfragen zu verlangsamen, anstatt sie abzulehnen. Ein Kontingent ist normalerweise ein größeres Kontingent über einen längeren Zeitraum, beispielsweise 10.000 Anrufe pro Monat im Rahmen eines Preisplans.

Warum APIs es brauchen

  • Stabilität: Verkehrsspitzen können Datenbanken oder nachgelagerte Dienste nicht überlasten.
  • Fairness: Ein schwerer Kunde kann die anderen nicht verhungern lassen.
  • Sicherheit: begrenzt die Verlangsamung von Brute-Force-Anmeldeversuchen und Scraping.
  • Kostenkontrolle: Teure Vorgänge wie KI-Modellaufrufe bleiben im Rahmen des Budgets.

Die Ratenbegrenzung ist eine Kernkontrolle in den OWASP API Security Top 10 bei uneingeschränktem Ressourcenverbrauch. Unser Leitfaden zum API-Testen mit Postman zeigt, wie Sie die wiederholten Anfragen senden, die zur Überprüfung erforderlich sind.

Token-Eimer

Stellen Sie sich einen Eimer vor, der bis zu 5 Token fasst. Für jede Anfrage wird ein Token benötigt. Es werden 1 Token pro Sekunde aufgefüllt, und der Bucket fasst nie mehr als 5. Wenn der Bucket leer ist, wird die Anfrage abgelehnt.

class TokenBucket:
    def __init__(self, capacity, refill_per_sec):
        self.capacity = capacity
        self.rate = refill_per_sec
        self.tokens = capacity
        self.last = 0.0

    def allow(self, now):
        elapsed = now - self.last
        self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
        self.last = now
        if self.tokens >= 1:
            self.tokens -= 1
            return True
        return False

Wir haben 7 Anfragen auf einmal gesendet, später weitere:

burst of 7 at t=0:  [True, True, True, True, True, False, False]
t=2.0:              [True, True, False]
t=10:               5 allowed of 10

Die ersten 5 gingen stoßweise durch, dann war der Eimer leer. Zwei Sekunden später waren 2 Token wieder aufgefüllt, sodass 2 weitere Anfragen erfolgreich waren. Nach einer langen Pause war der Bucket wieder voll, aber auf 5 begrenzt. Dieses Burst-dann-Steady-Verhalten passt zu echtem Datenverkehr, weshalb Token-Buckets in API-Gateways häufig vorkommen. Der Leaky Bucket ist ein enger Verwandter, der Anfragen mit einer festen Rate verarbeitet und die Ausgabe glättet, anstatt Bursts zuzulassen.

Festes Fenster vs. Schiebefenster

Ein Zähler mit festem Fenster ist der einfachste Ansatz: Lassen Sie 10 Anfragen pro Minute zu und setzen Sie den Zähler zurück, wenn sich die Minute ändert. Es weist einen bekannten Fehler an der Grenze auf. Wir haben 10 Anfragen bei 59,9 Sekunden und 10 weitere bei 60,0 Sekunden gesendet, mit einem Limit von 10 pro 60-Sekunden-Fenster:

fixed window allowed around boundary: 20 of 20
sliding log allowed around boundary:  10 of 20

Das feste Fenster ermöglichte alle 20 Anfragen in einer Zehntelsekunde, doppelt so schnell wie vorgesehen, da sie in zwei verschiedene Fenster fielen. Ein gleitendes Protokoll merkt sich die Zeit jeder aktuellen Anfrage und zählt die in den letzten 60 Sekunden, sodass korrekterweise nur 10 zugelassen wurden.

Der Kompromiss ist die Erinnerung. Ein Gleitprotokoll speichert einen Zeitstempel pro Anfrage. Die Schiebefenstertheke ist ein beliebter Mittelweg. Es schätzt die Rate, indem es die aktuelle und die vorherige Fensteranzahl mischt und dabei wenig Speicher mit guter Genauigkeit verbraucht.

Algorithmusvergleich

Algorithmus Platzt Genauigkeit Erinnerung
Festes Fenster Bis zu 2x an Grenzen Niedrig Sehr niedrig
Schiebescheit Nein Genau Hoch
Schiebefenstertheke Klein Gut Niedrig
Token-Eimer Bis zur Kapazitätsgrenze erlaubt Gut Niedrig
Undichter Eimer Geglättet Gut Niedrig

Worauf soll man beschränken?

  • API-Schlüssel oder Benutzer-ID: die fairste Option für authentifizierte APIs.
  • IP-Adresse: nützlich für öffentliche Endpunkte, aber viele Benutzer können eine IP teilen und Angreifer können sie rotieren.
  • Endpunkt: Teure Vorgänge wie Suche, Exporte oder Anmeldung verdienen strengere Grenzen.
  • Planstufe: Kostenlose und kostenpflichtige Kunden erhalten oft unterschiedliche Limits.

Anmeldeendpunkte benötigen besondere Sorgfalt. Begrenzen Sie sowohl nach Konto als auch nach IP, sodass Angreifer ihre Vermutungen nicht einfach über viele IPs oder viele Konten verteilen können.

Die 429-Antwort

Wenn ein Client das Limit überschreitet, wird HTTP 429 Too Many Requests zurückgegeben, nicht 500 oder 403. Fügen Sie Header ein, die dem Client mitteilen, was passiert ist und wann er es erneut versuchen soll. Unsere Simulation hat dieses Set für einen Kunden erstellt, für den keine Wünsche mehr offen waren:

HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30
Retry-After: 30

Retry-After ist ein Standard-HTTP-Header. Die RateLimit-*-Header stammen aus einem IETF-Entwurf und viele APIs verwenden ihre eigenen X-RateLimit-*-Varianten. Was auch immer Sie wählen, dokumentieren Sie es. Weitere Informationen zu Statuscodes finden Sie in unserem Spickzettel zu HTTP-Statuscodes.

Umgang mit Grenzen als Kunde

Ein erneuter Versuch unmittelbar nach einer 429 macht die Sache noch schlimmer. Wenn Tausende von Clients dies gleichzeitig tun, treffen sie in synchronisierten Wellen auf den Server. Die Lösung ist exponentielles Backoff mit Jitter: Warten Sie nach jedem Fehler länger und fügen Sie Zufälligkeit hinzu.

def backoff(attempt, base=0.5, cap=30, rng=random.Random(4)):
    return round(min(cap, base * 2 ** attempt) * rng.random(), 2)

[backoff(a) for a in range(6)]
# [0.12, 0.1, 0.79, 0.62, 0.53, 6.43]

Dies ist „vollständiger Jitter“: eine zufällige Wartezeit zwischen Null und einer exponentiell wachsenden Obergrenze. Die Wartezeiten sehen unregelmäßig aus, und das ist der Punkt. Kunden verteilen sich, anstatt es gemeinsam noch einmal zu versuchen. Wir haben den Zufallsgenerator gesät, damit die Ausgabe reproduziert werden konnte.

Client-Checkliste: Berücksichtigen Sie Retry-After, wenn es vorhanden ist, begrenzen Sie die Anzahl der Wiederholungsversuche, wiederholen Sie nur Anfragen, die sicher wiederholt werden können, und beobachten Sie den Header „Remaining-Requests“, damit Sie langsamer fahren können, bevor Sie das Limit erreichen.

Verteilte Ratenbegrenzung

Mit mehreren API-Servern hinter einem Load Balancer ermöglicht es jedem Server, der für sich allein arbeitet, einem Client, das Limit zu überschreiten, indem er Anfragen auf sie verteilt. Teams behalten Zähler normalerweise in einem gemeinsamen Speicher wie Redis, mit atomaren Operationen oder einem kurzen Skript, sodass nicht beide Server den letzten Token nehmen können. Gateways wie Kong, NGINX, Envoy und Cloud-API-Gateways stellen dies als Konfiguration bereit. Für diesen Artikel haben wir kein verteiltes Setup durchgeführt.

Ratengrenzen testen

  • Senden Sie Anfragen bis zum Limit und bestätigen Sie, dass sie erfolgreich sind.
  • Senden Sie noch eine und bestätigen Sie eine 429 mit korrekten Headern.
  • Warten Sie die Rücksetzzeit ab und bestätigen Sie, dass die Anfragen erneut erfolgreich sind.
  • Überprüfen Sie die Limits pro Schlüssel: Die Nutzung eines Clients darf einen anderen nicht blockieren.
  • Testen Sie die Grenze zwischen Fenstern auf das Double-Burst-Problem.
  • Verwenden Sie ein Ladetool, wie in Lasttest vs. Stresstest beschrieben, um das Verhalten bei starker Parallelität zu überprüfen.

Fügen Sie in Unit-Tests die aktuelle Zeit ein, wie es unsere Simulation mit now tut, damit Tests nie schlafen müssen.

Grenzen festlegen, mit denen Benutzer leben können

Die Auswahl der Zahlen ist genauso wichtig wie die Auswahl des Algorithmus. Beginnen Sie mit dem tatsächlichen Datenverkehr: Sehen Sie sich an, wie viele Anfragen Ihre wichtigsten legitimen Kunden pro Minute stellen, und legen Sie Grenzwerte fest, die bequem darüber liegen. Eine Beschränkung, die die normale Nutzung blockiert, führt zu Support-Tickets, nicht zur Sicherheit.

  • Veröffentlichen Sie die Grenzwerte in Ihrer API-Dokumentation, pro Endpunkt und pro Plan.
  • Vor dem Blockieren warnen. Header, die verbleibende Anfragen anzeigen, ermöglichen es brav verhaltenen Clients, selbstständig langsamer zu werden.
  • Bieten Sie Alternativen zu umfangreichen Abfragen an, wie z. B. Webhooks, Massenendpunkte oder größere Seiten.
  • Überwachen Sie die 429-Raten. Ein plötzlicher Anstieg kann einen Angriff, eine fehlerhafte Client-Version oder jetzt zu strenge Limits bedeuten.
  • Gewähren Sie absichtlich Ausnahmen, zum Beispiel erhöhte Grenzwerte für einen Partner, die in der Konfiguration aufgezeichnet und nicht fest codiert sind.

Entscheiden Sie außerdem, was mit Anfragen geschieht, die knapp über dem Limit eingehen. Einige APIs stellen eine kleine Anzahl zusätzlicher Anfragen kurzzeitig in die Warteschlange, anstatt sie abzulehnen, wodurch kurze Spitzen ausgeglichen werden. Andere geben wichtigen Endpunkten wie Zahlungen Vorrang vor weniger kritischen Endpunkten wie Analysen, sodass wichtiger Datenverkehr auch dann weiter fließt, wenn das System unter Druck steht.

Fazit

Eine gute Ratenbegrenzung ist ein Vertrag zwischen API und Client. Der Server wählt einen fairen Algorithmus aus, normalerweise einen Token-Bucket oder ein Schiebefenster, und erklärt seine Grenzen klar mit einem 429 und Retry-After. Der Kunde respektiert diese Signale und macht mit Jitter einen Rückzieher. Beginnen Sie mit großzügigen Limits pro API-Schlüssel, beobachten Sie die tatsächliche Nutzung und schränken Sie sie nur dort ein, wo es nötig ist.

Häufige Fragen

Was ist die API-Ratenbegrenzung?

Dabei handelt es sich um eine Grenze dafür, wie viele Anfragen ein Client in einer bestimmten Zeit an eine API stellen kann, beispielsweise 100 pro Minute. Anfragen, die das Limit überschreiten, werden abgelehnt oder verzögert.

Was bedeutet HTTP 429?

429 Too Many Requests bedeutet, dass der Client ein Ratenlimit überschritten hat. Die Antwort enthält häufig einen Retry-After-Header, der angibt, wie lange gewartet werden soll.

Was ist der Token-Bucket-Algorithmus?

Für jede Anfrage wird ein Token aus einem Bucket verwendet, der sich gleichmäßig bis zu einem Maximum auffüllt. Es ermöglicht kurze Bursts und erzwingt gleichzeitig eine durchschnittliche Rate.

Was ist der Unterschied zwischen Ratenbegrenzung und Drosselung?

Durch die Ratenbegrenzung werden Anfragen, die über dem Limit liegen, normalerweise abgelehnt. Durch die Drosselung werden sie häufig verlangsamt oder stattdessen in die Warteschlange gestellt. Die Begriffe werden häufig synonym verwendet.

Wie sollte ein Kunde mit Tariflimits umgehen?

Respektieren Sie Retry-After, wiederholen Sie den Vorgang mit exponentiellem Backoff und Jitter, begrenzen Sie die Anzahl der Wiederholungsversuche und verlangsamen Sie die Geschwindigkeit, wenn die verbleibenden Anforderungen zur Neige gehen.

Lerne weiter

Arbeiten Sie mit Stack Quora

Benötigen Sie Hilfe beim Testen, WordPress oder SEO?

Wir helfen Teams, bessere Software zu liefern und ihre Websites zu erweitern. Sagen Sie uns, woran Sie gerade arbeiten, und wir schlagen Ihnen einen klaren nächsten Schritt vor.

Lesen Sie weiter

Weitere Anleitungen finden Sie unter Tests, KI und moderne Entwicklung

Hat Ihnen dieser Artikel gefallen? Wählen Sie ein Thema und springen Sie direkt in unsere neuesten Tutorials.

Künstliche Intelligenz

KI-Halluzinationen erklärt: Warum Sprachmodelle Dinge erfinden und wie man sie reduziert

KI-Halluzinationen erklärt: Was sie sind, warum Sprachmodelle sie produzieren, gängige Typen, wie man sie mit Erdung und Eingabeaufforderungen reduz…

Artikel lesen →
DevOps

Erklärte Umgebungsvariablen: .env-Dateien, Geheimnisse und Konfiguration richtig gemacht

Umgebungsvariablen anhand von Python-Beispielen erklärt, die wir ausgeführt haben: Sie lesen und festlegen, warum jeder Wert ein String ist, .env-Da…

Artikel lesen →
Softwareentwicklung

API-Ratenbegrenzung erklärt: Algorithmen, Header und Behandlung von 429-Fehlern

API-Ratenbegrenzung anhand einer von uns durchgeführten Simulation erklärt: Token-Bucket, festes Fenster, gleitendes Fenster, 429 Antworten, Ratenbe…

Artikel lesen →
Testautomatisierung

Spott in Python: unittest.mock, Patch und die Fehler, die Tests zum Lügen machen

Mocking in Python mit unittest.mock, getestet: Mock und return_value, side_effect, Patchen, wo ein Name verwendet wird, Spezifikation und Autospec, …

Artikel lesen →
Softwaretests

Code-Abdeckung erklärt: Leitungs- und Zweigstellenabdeckung und was 100 % wirklich bedeutet

Erklärung der Codeabdeckung anhand eines echten Coverage.py-Laufs: Zeilen-, Zweig- und Bedingungsabdeckung, Lesen eines Berichts, warum bei 100 % Ab…

Artikel lesen →
Datenbanken & SQL

DELETE vs. TRUNCATE vs. DROP in SQL: Unterschiede, Rollback und Verwendungszweck

DELETE vs. TRUNCATE vs. DROP erklärt mit getestetem SQL: was jeweils entfernt wird, Rollback, Trigger, Identitätsrücksetzung, Geschwindigkeit und wi…

Artikel lesen →
Datenbanken & SQL

Erklärte SQL-Ansichten: Erstellen, nutzen und vermeiden Sie Fallstricke mit Beispielen

SQL-Ansichten anhand der von uns ausgeführten Abfragen erklärt: Erstellen einer Ansicht, Live-Ergebnisse, Ausblenden von Spalten, Leistung, aktualis…

Artikel lesen →
Softwareentwicklung

TypeScript-Schnittstelle vs. Typ: Echte Unterschiede, getestet mit dem Compiler

TypeScript-Schnittstelle vs. Typ, überprüft mit dem echten Compiler: Was beide können, was nur einer kann, Deklarationszusammenführung, Erweiterunge…

Artikel lesen →
Softwareentwicklung

Python *args und **kwargs erklärt: Flexible Funktionen mit klaren Beispielen

Python *args und **kwargs erklärt mit Code, den wir ausgeführt haben: Packen und Entpacken, Parameterreihenfolge, Nur-Schlüsselwort- und Nur-Positio…

Artikel lesen →
Softwareentwicklung

Python-Lambda-Funktionen: Syntax, tatsächliche Verwendung und wann man sie nicht verwendet

Python-Lambda-Funktionen erklärt mit Code, den wir ausgeführt haben: Syntax, Sortierung mit Schlüssel, Karte und Filter, Abschlüsse, die Late-Bindin…

Artikel lesen →
Künstliche Intelligenz

Was sind KI-Agenten? Wie sie funktionieren, mit einer einfachen Agentenschleife, die Sie ausführen können

Was sind KI-Agenten? Eine einfache Anleitung zur Agentenschleife, zu Tools, Speicher und Leitplanken, mit einer kleinen Python-Schleife, die wir aus…

Artikel lesen →
DevOps

Überwachung vs. Beobachtbarkeit: Der wahre Unterschied, mit Protokollen, Metriken und Traces

Überwachung vs. Beobachtbarkeit erklärt: bekannte und unbekannte Fehler, Protokolle, Metriken und Spuren, eine exemplarische Vorgehensweise für Chec…

Artikel lesen →
DevOps

Docker-Volumes vs. Bind Mounts: Containerdaten auf die richtige Art und Weise beibehalten

Docker-Volumes vs. Bind-Mounts erklärt: Warum Containerdaten verschwinden, benannte Volumes, Bind-Mounts, tmpfs, Compose-Beispiele, Backups, Berecht…

Artikel lesen →
Testautomatisierung

TDD vs. BDD: Hauptunterschiede, eine Funktion, die auf beide Arten entwickelt wurde und wann sie jeweils verwendet werden sollte

TDD vs. BDD erklärt mit einer Rabattfunktion, die in beide Richtungen aufgebaut ist: Rot-Grün-Refaktor mit Code, den wir ausgeführt haben, Gegeben-W…

Artikel lesen →
Softwareentwicklung

Git merge vs rebase: Unterschiede, Beispiele und wann man was nutzt

Git merge vs rebase erklärt mit echter Log-Ausgabe, einer Vergleichstabelle, der goldenen Regel des Rebase und einem sicheren Team-Workflow.

Artikel lesen →
Softwareentwicklung

Python List Comprehension: Syntax, Beispiele und wann man darauf verzichtet

Python List Comprehension erklärt: Syntax, Filter, if-else, verschachtelte Schleifen, gemessene Zeiten und Fälle, in denen eine normale for-Schleife…

Artikel lesen →
Datenbanken & SQL

SQL Joins erklärt mit Beispielen (Inner, Left, Right, Full)

SQL Joins Schritt für Schritt mit Beispieltabellen und Abfragen verstehen: INNER, LEFT, RIGHT, FULL, CROSS und SELF, plus typische Fehler und Perfor…

Artikel lesen →