Rate Limiting im API Management
September 16, 2022
Mit der Entwicklung des Internets haben immer mehr Unternehmen begonnen, Cloud-native und Microservices zu nutzen. Aufgrund der technischen Merkmale von Cloud-native und Microservices müssen wir jedoch Hunderte von verschiedenen Diensten gleichzeitig verwalten. Daher müssen wir nicht nur den reibungslosen Betrieb des gesamten Systems sicherstellen, sondern auch die Sicherheit und Stabilität jedes API-basierten Dienstes gewährleisten.
Die Rate Limiting (Ratenbegrenzung) ist eine der wichtigsten Lösungen, um die Stabilität von API-basierten Diensten zu gewährleisten. Allerdings würde die Anwendung extrem aufgebläht werden, wenn jeder Dienst eine eigene Ratenbegrenzung benötigt. Als Eingangs- und Ausgangspunkt für den gesamten Datenverkehr in der digitalen Welt hilft das API-Gateway dabei, eine einheitliche API-Verwaltung für alle Dienste zu erreichen. Es schützt den stabilen Betrieb der Systemdienste. In diesem Artikel zeigen wir, wie wir Ratenbegrenzung durch das Apache APISIX API-Gateway erreichen, und beschreiben Strategien und Techniken zur Ratenbegrenzung.
Was ist Ratenbegrenzung?
Ratenbegrenzung ist eine Strategie zur Steuerung des Internetverkehrs und zur Maximierung des Durchsatzes. Durch die Verwendung von Ratenbegrenzung werden nur Anfragen unter bestimmten Einschränkungen zugelassen, während zusätzliche Anfragen, die die Einschränkung überschreiten, in eine Warteschlange gestellt, priorisiert herabgestuft oder sogar abgelehnt oder verworfen werden. Ratenbegrenzung schützt das System auch vor unerwarteten Vorfällen wie Verkehrsspitzen oder böswilligen Angriffen und ermöglicht es dem System, konsistente und stabile Dienste bereitzustellen.
Ein Beispiel: Wenn ein viraler Tweet einen Verkehrsanstieg verursacht, muss Twitter eine Ratenbegrenzung einführen, um Serverabstürze aufgrund von Überlastung zu verhindern.
Warum wird Ratenbegrenzung benötigt?
Zunächst betrachten wir einige einfache Anwendungsfälle aus dem realen Leben, in denen Ratenbegrenzung verwendet wird. Zum Beispiel können Touristenattraktionen nur eine bestimmte Anzahl von Ferientickets verkaufen. Ebenso müssen wir in beliebten Restaurants oft im Voraus reservieren oder lange warten, bevor wir das Essen genießen können.
Im API-Gateway bietet Ratenbegrenzung ebenfalls viele Vorteile. Ratenbegrenzung setzt bestimmte Einschränkungen für unsere API-basierten Dienste, sichert deren reibungslosen Betrieb und vermeidet unnötige Verluste durch Serverabstürze aufgrund von Verkehrsspitzen. Hier sind fünf verschiedene praktische Einschränkungen aufgeführt:
- Begrenzung der Anfragegeschwindigkeit.
- Begrenzung der Anzahl der Anfragen pro Zeiteinheit.
- Verzögerung von Anfragen.
- Ablehnung von Client-Anfragen.
- Begrenzung der Antwortgeschwindigkeit.
Wann wird Ratenbegrenzung benötigt?
Zusammen mit Identifikation und Authentifizierung kann Ratenbegrenzung ihre Vorteile am besten maximieren und die Verfügbarkeit des Systems auf folgende Weise verbessern:
- Vermeidung von böswilligen Angriffen.
- Sicherstellung des stabilen Betriebs des Systems und Vermeidung von Serverabstürzen aufgrund von Verkehrsspitzen.
- Verhinderung von Serverabstürzen aufgrund von Anfragespitzen, die durch Fehler in Upstream- oder Downstream-Diensten verursacht werden.
- Vermeidung zu häufiger teurer API-Aufrufe.
- Reduzierung unnötiger Ressourcenverschwendung durch Begrenzung der Häufigkeit von API-Aufrufen.
Die Theorie hinter der Ratenbegrenzung
In den vorherigen Abschnitten haben wir die Vorteile der Ratenbegrenzung vorgestellt. In diesem Abschnitt wollen wir die Theorien dahinter erkunden! Die Implementierung der Ratenbegrenzung auf niedriger Ebene wird durch spezifische Algorithmen erreicht. Die häufig verwendeten Algorithmen sind:
- Zähleralgorithmus
- Festes Fenster
- Gleitendes Fenster
- Leaky-Bucket-Algorithmus
- Token-Bucket-Algorithmus
Zähleralgorithmus
Der Zähleralgorithmus ist relativ einfach zu verstehen und hat zwei Varianten:
Die erste Variante ist der Festes-Fenster-Algorithmus, der einen Zähler in einer festen Zeiteinheit verwaltet und den Zähler auf Null zurücksetzt, wenn die Zeiteinheit abgelaufen ist.
Die zweite Variante ist der Gleitendes-Fenster-Algorithmus, der eine Verbesserung des ersten Algorithmus darstellt. Er umfasst die folgenden Schritte:
- Unterteilung der Zeiteinheiten in mehrere Intervalle (jedes wird als Block bezeichnet).
- Jeder Block hat einen Zähler; jede eingehende Anfrage erhöht den Zähler um 1.
- Nach einer festgelegten Zeit bewegt sich dieses Zeitfenster um einen Block vorwärts.
- Es berechnet die Gesamtzahl der Anfragen in diesem Zeitfenster, indem es alle Zähler der Blöcke im Zeitfenster summiert; wenn die Gesamtzahl der Anfragen die Einschränkung überschreitet, werden alle Anfragen in diesem Zeitfenster verworfen.
Leaky-Bucket-Algorithmus
Stellen Sie sich einen undichten Eimer vor; alle Anfragen würden sich zunächst in einer Warteschlange ansammeln, und dann würde der undichte Eimer sie mit einer konstanten Rate versenden.
Wenn die Anfragen die Kapazität des Eimers überschreiten, würde das System alle überlaufenden Anfragen ablehnen und verwerfen. Der Leaky-Bucket-Algorithmus kann die Anfragegeschwindigkeit begrenzen und sicherstellen, dass alle Anfragen mit einer konstanten Rate versendet werden, was einen einfachen Eingang, aber einen schweren Ausgang schafft.
Die Kernschritte dieses Algorithmus:
- Alle Anfragen werden in einem Eimer mit fester Größe gespeichert.
- Der Eimer sendet Anfragen mit einer konstanten Rate, bis der Eimer leer ist.
- Wenn der Eimer voll ist, wird das System alle zusätzlichen Anfragen verwerfen.
Token-Bucket-Algorithmus
Der Token-Bucket-Algorithmus besteht aus zwei Teilen: Token-Erzeugung und -Verwerfung. Der Token-Bucket erzeugt Token mit einer konstanten Rate und speichert sie in einem festen Speichereimer. Wenn eine Anfrage den Token-Bucket durchläuft, nimmt die Anfrage ein oder mehrere Token. Wenn die Anzahl der Token im Token-Bucket die maximale Kapazität erreicht, wird der Token-Bucket neu erzeugte Token verwerfen. Außerdem wird der Speichereimer eingehende Anfragen ablehnen, wenn keine Token mehr vorhanden sind.
Die Kernschritte des Token-Bucket-Algorithmus:
- Der Token-Bucket erzeugt Token mit einer konstanten Rate und legt sie in den Speichereimer.
- Wenn der Token-Bucket voll ist, werden neu erzeugte Token direkt verworfen. Wenn eine Anfrage eintrifft, nimmt sie ein oder mehrere Token aus dem Speichereimer.
- Wenn keine Token mehr im Token-Bucket vorhanden sind, wird das System alle eingehenden Anfragen ablehnen.
Ratenbegrenzung über das API-Gateway erreichen
Wenn nur wenige API-basierte Dienste verwaltet werden müssen, könnten wir die Ratenbegrenzungsalgorithmen direkt im Dienst implementieren. Wenn Sie beispielsweise Go verwenden, um Ihr System zu entwickeln, könnten Sie tollbooth
oder golang.org/x/time/rate
verwenden, um die Algorithmen zu implementieren. Wenn Sie Lua verwenden, könnten Sie NGINX's limit_req
, limit_conn
und Lua-resty-limit-traffic
Module verwenden, um die Algorithmen zu implementieren.
Wenn die Ratenbegrenzung auf einem API-basierten Dienst implementiert wird, werden die Einschränkungen der Ratenbegrenzung vom Dienst selbst festgelegt, und jeder Dienst könnte unterschiedliche Einschränkungen haben. Diese Einschränkungen und Unterschiede könnten zu Management-Problemen führen, wenn die Anzahl der API-basierten Dienste erheblich zunimmt. Zu diesem Zeitpunkt könnten wir das API-Gateway nicht mehr verwenden, um alle API-Dienste einheitlich zu verwalten. Sie könnten auch nicht verwandte Geschäftsfunktionen auf dem Gateway implementieren, wie Identifikation, Authentifizierung, Protokollierung, Beobachtbarkeit usw., wenn Sie das API-Gateway verwenden, um Ratenbegrenzungsprobleme zu lösen.
Apache APISIX ist ein dynamisches, Echtzeit-, Hochleistungs-Cloud-native-Gateway. APISIX unterstützt derzeit über 80 verschiedene Plugins und hat bereits ein reiches Ökosystem aufgebaut. Wir können den Datenverkehr von API-basierten Diensten mithilfe von APISIX-Plugins verwalten, darunter limit-req
, limit-conn
und limit-count
. Hier werde ich einen Anwendungsfall teilen, um die Verwendung von APISIX-Ratenbegrenzungs-Plugins zu demonstrieren.
Angenommen, es gibt einen API-basierten Dienst (/user/login
), der Benutzern beim Anmelden hilft. Um böswillige Angriffe und Ressourcenknappheit zu vermeiden, müssen wir die Ratenbegrenzungsfunktion aktivieren, um die Stabilität des Systems zu sichern.
Anfragen begrenzen
Das limit-req
Plugin begrenzt die Anfragegeschwindigkeit, verwendet den Leaky-Bucket-Algorithmus und bindet es an entsprechende Routen oder spezifische Kunden.
Wir können direkt die Admin-API von APISIX verwenden, um eine solche Route zu erstellen:
X-API-Key
ist der admin_key in der APISIX-Konfiguration.
curl http://127.0.0.1:9080/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["POST"],
"uri": "/user/login",
"plugins": {
"limit-req": {
"rate": 3,
"burst": 2,
"rejected_code": 503,
"key": "remote_addr"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
Die Bedeutung dieses Codeausschnitts: Wir verwenden die IP-Adresse des Clients als Anforderung, um die Anfragegeschwindigkeit zu begrenzen.
- Wenn die Anfragegeschwindigkeit kleiner als 3 Anfragen/Sekunde (
rate
) ist, dann ist die Anfrage normal; - Wenn die Anfragegeschwindigkeit größer als 3 Anfragen/Sekunde und kleiner als 5 Anfragen/Sekunde (
rate+burst
) ist, werden wir diese überschüssigen Anfragen herabstufen; - Wenn die Anfragegeschwindigkeit größer als 5 Anfragen/Sekunde (
rate+burst
) ist, werden alle Anfragen, die die maximale Einschränkung überschreiten, den HTTP-Code 503 zurückgeben.
Wenn Sie mehr über limit-req
erfahren möchten, lesen Sie bitte dieses Dokument: APISIX limit-req
Verbindungen begrenzen
Das limit-conn
Plugin begrenzt parallele Anfragen (oder parallele Verbindungen). Das folgende ist ein Beispielcodeausschnitt, um dieses Plugin für /user/login
zu aktivieren:
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["POST"],
"uri": "/user/login",
"id": 1,
"plugins": {
"limit-conn": {
"conn": 3,
"burst": 2,
"default_conn_delay": 0.1,
"rejected_code": 503,
"key": "remote_addr"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
Die Bedeutung dieses Codeausschnitts: Wir verwenden die IP-Adresse des Clients als Anforderung, um parallele Anfragen zu begrenzen.
- Wenn die parallelen Verbindungen desselben Clients weniger als 3 (
conn
) sind, dann antwortet es mit dem normalen Status 200; - Wenn die parallelen Verbindungen mehr als 3 (
conn
) aber weniger als 5 (conn+burst
) sind, werden wir die überlaufenden Anfragen verlangsamen und die Verzögerungszeit um 0,1 Sekunden erhöhen; - Wenn die parallelen Verbindungen mehr als 5 (
conn+burst
) sind, wird diese Anfrage abgelehnt und gibt den HTTP-Code 503 zurück.
Wenn Sie mehr über limit-conn
erfahren möchten, lesen Sie bitte dieses Dokument: APISIX limit-conn
Anzahl begrenzen
Das limit-count
Plugin ähnelt der Ratenbegrenzung der Github-API; es begrenzt die Gesamtzahl der Anfragen in einem bestimmten Zeitintervall und gibt die verbleibende Anzahl der Anfragen im HTTP-Header zurück. Das folgende ist ein Beispielcodeausschnitt, um dieses Plugin für /user/login
zu aktivieren:
curl -i http://127.0.0.1:9080/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/user/login",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"policy": "local"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
}
}'
Die Bedeutung dieses Codeausschnitts: Wir verwenden die IP-Adresse des Clients als Anforderung, um die Anzahl der Anfragen zu begrenzen; der Zähler wird lokal im Speicher gespeichert.
Wenn es mehr als 3 (count
) Anfragen innerhalb von 60 Sekunden (time_window
) gibt, werden die Anfragen, die mehr als 3 Mal gesendet werden, den HTTP-Code 503 (rejected_code
) zurückgeben.
Wenn Sie mehr über limit-count
erfahren möchten, lesen Sie bitte dieses Dokument: APISIX limit-count
Die Vorteile der Ratenbegrenzung mit Apache APISIX
Wenn wir NGINX verwenden, um den Datenverkehr zu verwalten, und die Anzahl der API-Anfragen einen plötzlichen Anstieg des Datenverkehrs verursacht, dann würde NGINX seine Schwächen offenbaren, und eine dieser Schwächen ist, dass es Konfigurationen nicht dynamisch laden kann. Andererseits unterstützen APISIX-Dienste (wie Route und Service) die Konfigurations-Hot-Reloading. Selbst bei einem plötzlichen Anstieg des Datenverkehrs könnte APISIX die Ratenbegrenzung und andere Sicherheits-Plugins sofort anpassen. Dank des Watch-Mechanismus von etcd kann APISIX die Datenebene innerhalb von Millisekunden aktualisieren, ohne die Dienste neu zu laden.
Darüber hinaus unterstützt APISIX auch clusterweite Ratenbegrenzung. Zum Beispiel könnten wir limit-count
verwenden, um die Konfiguration von policy
auf redis
oder redis-cluster
zu ändern. Daher könnten wir clusterweite Raten begrenzen, indem wir Berechnungsergebnisse zwischen verschiedenen APISIX-Knoten teilen.
Als DevOps würde die Verwendung eines grafischen Dashboards zur Verwaltung aller API-Dienste die Produktivität steigern. APISIX bietet ein übersichtliches visuelles Dashboard zur Verwaltung, um die Konfiguration von APIs viel bequemer zu machen.
Fazit
Ratenbegrenzung ist ein häufiges Bedürfnis in tatsächlichen Geschäftsszenarien und ein entscheidender Weg, um das System vor Verkehrsspitzen zu schützen und seinen reibungslosen Betrieb sicherzustellen. Ratenbegrenzung ist nur ein Teil der API-Dienstverwaltung; wir könnten auch viele andere Technologien verwenden, um wichtige Sicherheitsunterstützung zu bieten und die Benutzererfahrung zu verbessern.