Rate Limiting für Multi-Tenant-APIs: Fair-Use-Quotas, ohne gute Kunden zu bestrafen
Rate Limiting gehört zu den Infrastruktur-Entscheidungen, die am ersten Tag einfach aussehen und Dich am tausendsten Tag hart treffen. Du setzt eine globale Obergrenze - sagen wir 1.000 Requests pro Minute pro API-Key - und gratulierst Dir dazu, das System geschützt zu haben. Dann startet Dein größter Kunde um 2 Uhr nachts den Report-Export zum Quartalsende, läuft in das Limit, und Dein Support-Postfach ist vor dem Frühstück voll.
API Rate Limiting in einer Multi-Tenant-Umgebung ist in erster Linie kein technisches Problem. Es ist ein Produkt- und Fairness-Problem, das nebenbei sorgfältige Technik verlangt. Das Ziel: Deine Infrastruktur vor Missbrauch schützen und gleichzeitig nie den Eindruck erzeugen, dass ein zahlender Kunde dafür bestraft wird, Dein Produkt erfolgreich zu nutzen.
Dieser Beitrag behandelt die praktischen Design-Entscheidungen: wie Du über Quotas pro Tenant nachdenkst, wie Du ein Token-Bucket-System implementierst, das Bursts sauber verkraftet, und wie eine Fair-Use-Policy in Worten und im Code aussehen sollte.
Warum globale Rate Limits bei Multi-Tenant-APIs scheitern
Ein einziges gemeinsames Limit behandelt jeden Tenant gleich. Das klingt fair, bis Du die tatsächlichen Nutzungsmuster ansiehst. In den meisten SaaS-Produkten kommen 80 % des Traffics von 20 % der Tenants - und genau diese Spitzengruppe sind in der Regel Deine wertvollsten Accounts. Ein globales Limit, das den Missbrauch durch einen kleinen Free-Tier-Kunden stoppt, stoppt genauso den legitimen Batch-Job eines Enterprise-Vertrags, der zehnmal so viel pro Monat zahlt.
Der zweite Fehlermodus ist Burst-Blindheit. Ein Tenant, der eine Minute lang 60 Requests pro Sekunde sendet, verbraucht dieselbe Quota wie einer, der eine Stunde lang 1 Request pro Sekunde schickt. Aus Sicht des Systems ist der Burst deutlich schwerer zu absorbieren: Er erzeugt Queueing-Druck, Datenbank-Contention und Latenzspitzen für alle anderen. Wenn Dein Limit aber nur als Requests pro Stunde ausgedrückt ist, hast Du keine Möglichkeit, die beiden Muster zu unterscheiden.
Rate Limiting für Multi-Tenant-APIs muss drei verschiedene Probleme gleichzeitig lösen: gemeinsam genutzte Infrastruktur vor Überlast schützen, verhindern, dass ein einzelner Tenant die anderen verdrängt, und legitime Use Cases, die in die gekaufte Kapazität eines Tenants passen, niemals unterbrechen.
Token Buckets: das passende mentale Modell
Der Token-Bucket-Algorithmus ist das nützlichste mentale Modell für dieses Problem. Jeder Tenant bekommt einen Bucket mit fester Kapazität (die Burst-Obergrenze), der mit konstanter Rate wieder aufgefüllt wird (der nachhaltige Durchsatz). Jeder API-Request verbraucht einen oder mehrere Tokens. Ist der Bucket leer, werden Requests entweder eingereiht oder abgelehnt.
Wertvoll wird der Token Bucket dadurch, dass er Bursts korrekt behandelt. Ein Tenant, der eine Stunde still war, kommt mit einem vollen Bucket an der API an und kann sofort einen großen Export-Job abfeuern. Ein Tenant, der permanent Last erzeugt, hat einen nur teilweise gefüllten Bucket und wird proportional gedrosselt. Der Algorithmus belohnt effiziente Nutzungsmuster von sich aus, ohne dass Du jedes Tenant-Verhalten im Vorfeld klassifizieren musst.
Die wichtigsten Parameter, die Du pro Tenant setzt, sind die Bucket-Kapazität (maximaler Burst), die Refill-Rate (nachhaltige Requests pro Sekunde) und das Refill-Intervall (wie oft Tokens hinzugefügt werden). Für eine typische B2B-SaaS-API ist ein sinnvoller Startpunkt eine Bucket-Kapazität von 200 Tokens mit einem Refill von 20 pro Sekunde. Das erlaubt eine kurze Spitze von bis zu 200 Requests und hält über längere Zeiträume 1.200 pro Minute aus.
In Redis können sowohl das INCR-and-EXPIRE-Muster als auch ein Lua-Skript mit Sliding Window einen Token Bucket effizient annähern. Bibliotheken wie der Rate Limiter aus Symfony HttpFoundation übernehmen die Buchhaltung, aber die entscheidende Einsicht ist: Der Bucket-State liegt pro Tenant-Key, nicht in einem gemeinsamen globalen Zähler.
Quota-Stufen entwerfen, die zu Deinem Pricing passen
Rate Limits sollten die kommerzielle Beziehung widerspiegeln, nicht nur die technische Randbedingung. Wenn Du drei Plan-Stufen hast, sollte jede Stufe explizit dokumentierte Quota-Parameter haben, die zu dem passen, was Kunden bezahlt haben.
Eine sinnvolle Struktur für ein B2B-SaaS-Produkt könnte so aussehen: Die Starter-Stufe bekommt eine moderate Burst-Obergrenze und eine niedrige nachhaltige Rate - genug für ein kleines Team, das die API interaktiv nutzt, aber nicht genug für große Batch-Jobs. Die Growth-Stufe bekommt eine deutlich höhere Obergrenze und eine Rate, die moderate Automatisierung trägt. Die Enterprise-Stufe bekommt ein pro Vertrag verhandeltes Limit, oft mit einem eigenen Rate-Limit-Key, der sich den Redis-Keyspace überhaupt nicht mit kleineren Tenants teilt.
Die konkreten Zahlen sind weniger wichtig als das Prinzip: Jede Stufe sollte Burst-Kapazität klar von nachhaltigem Durchsatz trennen, und die Enterprise-Stufe sollte nie über denselben Infrastruktur-Pfad limitiert werden wie ein kostenloser Account. Wenn ein Free-Tier-Kunde mit schlechtem Code auf die API einprügelt, darf das keine messbare Latenz für Deine Enterprise-Accounts erzeugen.
Diese Trennung ist beim Systementwurf wichtiger, als die meisten Teams annehmen. Wenn Du die Infrastruktur jetzt baust, überlege, sie von Anfang an mit physisch getrennten Redis-Instanzen oder Namespaces pro Plan-Stufe zu strukturieren. Diese Trennung später nachzurüsten, wenn ein Enterprise-Kunde schon live ist, ist eine schmerzhafte Migration.
Die Fair-Use-Policy: es aufzuschreiben zählt
Ein technisches Rate Limit ohne schriftliche Fair-Use-Policy erzeugt Support-Probleme. Wenn ein Kunde in ein Limit läuft, muss er verstehen, warum, was es bedeutet und was er dagegen tun kann. Wenn in Deiner Dokumentation nur "1.000 Requests pro Minute" steht, ohne das Burst-Verhalten zu erklären, sind Kunden verwirrt, wenn sie nach einer längeren Idle-Phase bereits bei 800 Requests pro Minute gedrosselt werden.
Eine gute Fair-Use-Policy beantwortet vier Fragen: Was zählt als Request (zählt ein Batch-Endpoint, der 100 Elemente verarbeitet, als 1 oder als 100?), wie werden Burst-Limits berechnet, was passiert beim Erreichen der Limits (Ablehnung, Queueing oder degradierte Antwort), und wie kann ein Kunde eine temporäre oder dauerhafte Erhöhung beantragen.
Der dritte Punkt - was beim Erreichen der Limits passiert - verdient besondere Aufmerksamkeit. Eine harte 429-Antwort ohne Retry-Information ist das schlechteste Ergebnis. Gib mindestens einen Retry-After-Header zurück, der angibt, wann der Bucket wieder Tokens hat. Besser noch: Liefere den aktuellen Bucket-State in jedem Response-Header, damit sich gut gebaute Clients selbst drosseln können, bevor sie an die Obergrenze stoßen. Die API von GitHub ist eine nützliche Referenz: Jede Antwort enthält X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset, sodass Clients ihr eigenes Tempo steuern können.
Die zentrale Design-Entscheidung ist hier, ob Du Requests einreihst oder ablehnst. Queueing ist freundlicher für Nutzer, erhöht aber die Komplexität und kann schlechtes Client-Verhalten verschleiern. Ablehnen ist einfacher, verlangt aber von Clients eine Retry-Logik. Für die meisten B2B-APIs ist Ablehnung mit einem aussagekräftigen 429 und passenden Headern der richtige Default, während Queueing als Enterprise-Option für Batch-Workloads verfügbar bleibt.
Abgestuftes Throttling statt harter Stopps
Ein pauschales Rate Limit hat ein binäres Ergebnis: Requests gehen durch oder sie scheitern. Abgestuftes Throttling fügt eine Zwischenstufe ein, in der Requests langsamer werden, bevor sie stoppen. So bekommt der Client Zeit, das zu bemerken und nachzusteuern, ohne harten Fehlschlag.
In der Praxis funktioniert abgestuftes Throttling über zwei Schwellen. Die erste Schwelle, etwa 80 % des nachhaltigen Limits, löst eine sanfte Warnung in den Response-Headern aus. Die zweite Schwelle, 100 %, löst den 429 aus. Eine gut instrumentierte Client-Bibliothek sieht den Warn-Header und reduziert ihre Request-Rate automatisch. Die meisten Clients sind nicht so ausgereift, aber serverseitige Warnungen geben technischen Teams zumindest etwas, das sie in ihren Logs erkennen können, bevor Nutzer eine Verschlechterung merken.
Für wertvolle Enterprise-Tenants lohnt es sich, eine temporäre Burst-Reserve über dem normalen Limit zu implementieren, die über die Zeit abgebaut wird. Ein Tenant, der weniger als 30 Sekunden lang 50 % über seiner nachhaltigen Rate liegt, bekommt gar keinen 429 - die Infrastruktur kann die Spitze absorbieren. Ein Tenant, der fünf Minuten lang 50 % über seiner Rate bleibt, wird gedrosselt. Diese Unterscheidung trennt legitimen Burst-Traffic von einem außer Kontrolle geratenen Prozess und reduziert Fehlalarme beim Throttling für Deine besten Kunden deutlich.
Gemeinsame Infrastruktur, getrennte Verrechnung
Das schwierigste Multi-Tenancy-Problem ist nicht, einzelne Tenants zu limitieren, sondern zu verhindern, dass der Traffic eines Tenants die Erfahrung eines anderen verschlechtert, noch bevor Limits überhaupt greifen. Rate Limiting arbeitet am Edge, aber Datenbank-Connection-Pooling, Cache-Eviction und Background-Job-Queues sind alles gemeinsam genutzte Ressourcen, die Noisy-Neighbour-Effekte bei Durchsätzen weit unterhalb Deiner Rate-Limit-Obergrenze erzeugen können.
Zwei Praktiken helfen hier. Erstens: Implementiere neben API-Rate-Limits auch Limits für Datenbank-Verbindungen pro Tenant. Ein Tenant, der einen schweren Report fährt, sollte nicht Deinen kompletten Connection Pool belegen, unabhängig davon, ob er innerhalb seiner API-Quota liegt. Zweitens: Verlagere teure Endpoints - Report-Generierung, Daten-Exporte, Bulk-Operationen - auf einen dedizierten Worker-Pool mit eigener Queue und Concurrency-Limits pro Tenant.
Hier zahlt sich custom software development aus, das Multi-Tenancy von Anfang an mitdenkt. Isolation pro Tenant in ein System nachzurüsten, das mit Single-Tenant-Denke gebaut wurde, ist teuer und fehleranfällig. Wenn Du eine neue API baust oder eine bestehende skalierst, ist der Zeitpunkt für den Entwurf der Isolationsgrenzen vor den Enterprise-Verträgen mit SLA-Zusagen.
Monitoring: was Du messen solltest
Rate Limiting ist nur dann nützlich, wenn Du weißt, wann es greift und warum. Die Metriken, die Du verfolgen solltest, sind die 429-Rate pro Tenant (nicht nur aggregiert), der Anteil der Tenants, die regelmäßig über 80 % ihres nachhaltigen Limits liegen, die Verteilung der Burst-Events nach Dauer und Größe, und der Retry-Traffic, der durch 429-Antworten entsteht.
Die 429-Rate pro Tenant zeigt Dir, welche Accounts in Reibung laufen. Wenn ein wertvoller Account täglich in Limits läuft, ist das ein Vertriebsgespräch über ein Upgrade der Stufe und kein Support-Ticket zum Abhaken. Die Retry-Traffic-Metrik zeigt Dir, ob sich Deine Clients gut verhalten - Exponential Backoff und Jitter sind leicht empfohlen, aber oft nicht implementiert.
Eine Alerting-Regel, die sich lohnt: Wenn ein einzelner Tenant mehr als 5 % des aggregierten API-Traffics erzeugt, informiere Dein Team. Diese Konzentration ist ungewöhnlich genug, um ein Gespräch mit dem Kunden zu rechtfertigen, unabhängig davon, ob er innerhalb seiner Limits bleibt.
Häufige Fehler
Nach API-Key statt nach Tenant limitieren. Ein einzelner Tenant mit fünf API-Keys hat effektiv das Fünffache seines angegebenen Limits. Rate Limits sollten über alle Keys eines Tenants hinweg aggregieren, mit der Tenant-ID als primärem Bucket-Key.
Retries nicht im Limit berücksichtigen. Wenn ein Client einen fehlgeschlagenen Request wiederholt, verbraucht dieser Retry ein weiteres Token. Kaskadierende Retry-Stürme können eine temporäre Überlast in eine dauerhafte verwandeln. Rate-Limit-Antworten sollten genug Information enthalten, damit gut gebaute Clients vor dem Retry warten.
Limits so hoch setzen, dass sie niemand merkt. Wenn Dein Limit weit über dem liegt, was irgendein Tenant tatsächlich nutzt, bewirkt es nichts. Liegt es zu nah an der durchschnittlichen Nutzung, feuert es dauernd. Setze Limits etwa auf das Drei- bis Fünffache des 95. Perzentils der nachhaltigen Nutzung je Stufe und überprüfe die Zahlen quartalsweise, während Produkt und Kundenbasis wachsen.
Webhook- und Async-Traffic vergessen. Wenn Deine API Webhooks oder asynchrone Callbacks umfasst, erzeugen diese Rückverkehr von Kundensystemen zu Deinem. Das ist oft überhaupt nicht rate-limitiert, und ein Kunde mit einem langsamen Webhook-Empfänger kann einen Queue-Aufbau erzeugen, der auf Deiner Seite wie ein Rate-Limit-Problem aussieht, in Wahrheit aber ein Delivery-Backlog ist.
Von dort starten, wo Du stehst
Wenn Deine API aktuell überhaupt keine Limits pro Tenant hat, beginne mit einem Redis-basierten Token Bucket auf der Tenant-ID, setze konservative Startwerte, ergänze die Response-Header und beobachte zwei Wochen, bevor Du irgendetwas verschärfst. Die meisten Teams stellen fest, dass eine Handvoll Tenants einen überproportionalen Anteil des Traffics erzeugt, und die Daten machen die richtigen Entscheidungen offensichtlich.
Wenn Du schon Limits hast, aber Beschwerden von legitimen Kunden bekommst, ist der übliche Grund eine Burst-Obergrenze, die im Verhältnis zu den echten Nutzungsmustern zu niedrig ist. Die Burst-Kapazität zu verdoppeln und die nachhaltige Rate gleich zu lassen, löst die meisten Fehlalarme beim Throttling, ohne die Infrastrukturlast merklich zu erhöhen.
Rate Limiting gut zu machen, ist eines dieser Details, die eine produktionsreife API von einem Prototyp unterscheiden. Es schützt Deine Infrastruktur, hält das System für alle Tenants fair und wird - wenn es durchdacht umgesetzt ist - für Kunden unsichtbar, die das Produkt so nutzen, wie es gedacht ist.
Wenn Du eine Multi-Tenant-API baust oder skalierst und eine Außenperspektive auf das Quota-Design, die Infrastruktur-Entscheidungen oder die Formulierung der Fair-Use-Policy möchtest, melde Dich unter hello@wolf-tech.io oder über wolf-tech.io. Das sind architektonische Entscheidungen mit langfristigen Folgen, und sie früh richtig zu treffen ist deutlich günstiger, als sie später unter Last zu reparieren.

