Praktische Strategien für GraphQL API Rate Limiting
January 4, 2024
Die Implementierung von Ratenbegrenzungen für REST-APIs ist relativ unkompliziert, da wir häufig URI-Pfade verwenden, um spezifische API-Ressourcen darzustellen, und HTTP-Methoden, um Operationen auf diesen Ressourcen anzugeben. Die Proxy-Schicht kann vordefinierte Ratenbegrenzungsregeln basierend auf diesen Informationen leicht durchsetzen.
Die Situation wird jedoch deutlich komplexer, wenn es um GraphQL-APIs geht. Lassen Sie uns untersuchen, wie diese Herausforderungen bewältigt werden können.
Einfache Szenarien
Im Gegensatz zu REST-APIs verwendet GraphQL eine eigene Abfragesprache. Es verlässt sich nicht mehr auf Pfade und HTTP-Methoden, um Ressourcen abzurufen und zu manipulieren, sondern vereinheitlicht Datenabfragen und Operationen unter Query und Mutation, wobei Query Daten abruft und Mutation Datenmanipulationen wie Erstellen, Aktualisieren und Löschen durchführt.
GET /users
GET /users/1
POST /users
PUT /users/1
DELETE /users/1
query { users { fullName } }
query { user(id: 1) { fullName } }
mutation { createUser(user: { lastName: "Jack" }) { id, fullName } }
mutation { updateUser (id: 1, update: { lastName: "Marry" }) { fullName } }
mutation { deleteUser (id: 1) }
Die obigen Beispiele verdeutlichen den Wechsel in den API-Abfragemethoden. Im Gegensatz zu REST ähnelt GraphQL dem Aufruf von Funktionen auf Ressourcen, wobei notwendige Eingabeparameter übergeben werden und die Antwort die abgefragten Daten enthält. Neben Unterschieden in den Abfragemethoden stellt GraphQL APIs typischerweise über einen einzigen Endpunkt (z.B. /graphql) bereit, wobei Abfragen und Eingabeparameter über den POST-Body gesendet werden.
Betrachten Sie das folgende Beispiel:
query {
users {
fullName
}
photos {
url
uploadAt
}
}
In diesem Szenario, das die Startseite eines Albums simuliert, fragt ein API-Aufruf an den Endpunkt /graphql
gleichzeitig sowohl die Benutzer- als auch die Fotolisten ab. Überlegen Sie nun, ob traditionelle Reverse-Proxy-Strategien, die auf der Ebene von Anfragen ausgeführt werden, weiterhin auf GraphQL-APIs anwendbar sind.
Die Antwort lautet nein. Traditionelle Reverse-Proxy-Server können GraphQL-API-Aufrufe, die die Abfragen selbst enthalten, nicht effektiv verarbeiten, was die Durchsetzung von Richtlinien wie Ratenbegrenzungen unmöglich macht. Für GraphQL-APIs erscheint die Granularität von "HTTP-Anfragen" zu grob.
Allerdings bietet das API-Gateway Apache APISIX integrierte Unterstützung für GraphQL zu HTTP-Funktionen. Administratoren können eine Abfrageanweisung vorkonfigurieren, sodass Clients sie direkt über einen HTTP-POST aufrufen können, ohne die Details von GraphQL zu verstehen, und nur die notwendigen Eingabeparameter bereitstellen müssen. Dies erhöht nicht nur die Sicherheit, sondern ermöglicht auch die Anwendung von HTTP-API-Richtlinien in diesem Kontext.
Effektiv verwandelt dies dynamische GraphQL-Abfragen in wissensbasierte statische Abfragen, die von API-Anbietern bereitgestellt werden, was sowohl Vor- als auch Nachteile mit sich bringt. Manchmal möchten wir möglicherweise nicht auf die dynamische Abfragefunktion von GraphQL verzichten. Lassen Sie uns die Diskussion anderer Szenarien fortsetzen.
Komplexe Szenarien
GraphQL verwendet seine spezialisierte Sprache für die Datenmodellierung und API-Beschreibung, was verschachtelte Datenstrukturen ermöglicht. Erweitern wir das vorherige Beispiel:
query {
photos(first: 10) {
url
uploadAt
publisher {
fullName
avatar
}
comments(first: 10) {
content
sender {
fullName
avatar
}
}
}
// users...
}
In diesem Fall, der das Abrufen der ersten 10 Fotos simuliert, einschließlich des Herausgebers für jedes Foto und der ersten 10 Kommentare mit ihren Absendern, muss der Backend-Dienst Abfragen verarbeiten, die mehrere Datenbanktabellen oder Aufrufe von Microservices betreffen. In solchen verschachtelten Abfrageszenarien steigt der Berechnungsdruck auf Backend-Dienste und Datenbanken exponentiell an, wenn die Datenmenge und die Verschachtelungsebenen zunehmen.
Um zu verhindern, dass komplexe Abfragen den Dienst überlasten, möchten wir möglicherweise solche Abfragen auf der Proxy-Ebene überprüfen und blockieren. Um diese Strategie anzuwenden, muss die Proxy-Komponente Abfrageanweisungen in strukturierte Daten parsen, sie durchlaufen, um verschachtelte Felder in jeder Ebene zu erhalten, und der gängigen Praxis von GraphQL folgen, Feldern Komplexitätswerte als Abfragekosten zuzuweisen. Globale Grenzen für die Gesamtabfragekomplexität können dann durchgesetzt werden. Für die obige Abfrage, unter der Annahme, dass jedes einzelne Feld einen Kostenwert von 1 hat:
10 * photo (url + uploadAt + publisher.fullName + publisher.avatar + 10 * comment (content + sender.fullName + sender.avatar))
10 * (1 + 1 + 1 + 1 + 10 * (1 + 1 + 1)) = 340
Mit einer Gesamtabfragekosten von 340 scheint dies akzeptabel zu sein, und wir können API-Abfragekostengrenzen basierend auf solchen Regeln konfigurieren. Wenn jedoch ein bösartiger Client versucht, Daten für 100 Fotos in einer einzigen Abfrage abzurufen, steigen die Abfragekosten auf 3400, überschreiten die vordefinierte Grenze und führen zu einer abgelehnten Anfrage.
Neben der Beschränkung der maximalen Kosten pro Client-Abfrage können zusätzliche Grenzen für Zeitintervalle festgelegt werden, z.B. dass Clients insgesamt 2000 Abfragen pro Minute durchführen dürfen und überschüssige Abfragen abgelehnt werden, um bösartige Crawler zu vereiteln.
Um solche Fähigkeiten zu implementieren, muss die Proxy-Komponente Abfragen parsen und Abfragekosten berechnen. API7 Enterprise unterstützt diese Funktionen, ermöglicht das dynamische Parsen von GraphQL-Abfragen und implementiert Benutzerratenbegrenzungen basierend auf Konfigurationen.
GraphQL-APIs stehen vor Herausforderungen auf der Proxy-Ebene, wo traditionelle Reverse-Proxys Schwierigkeiten haben, die Komplexität und Verschachtelungsbeziehungen innerhalb von GraphQL-Abfrageanweisungen effektiv wahrzunehmen und zu verarbeiten. Im Gegensatz dazu erweisen sich API-Gateway-Technologien als unschätzbar wertvoll, um diese Herausforderungen zu bewältigen, wobei API7 Enterprise eine ausgezeichnete Wahl sein kann.