Um Rate Limiting einfacher auszudrücken, handelt es sich um eine Technik, bei der wir die Anzahl der Anfragen begrenzen, die ein Benutzer oder Client innerhalb eines bestimmten Zeitrahmens an eine API stellen kann. Möglicherweise haben Sie in der Vergangenheit die Meldung „Ratenlimit überschritten“ erhalten, wenn Sie versucht haben, auf eine Wetter- oder eine Witz-API zuzugreifen. Es gibt viele Argumente dafür, warum man eine API begrenzen sollte, aber einige wichtige sind, sie fair zu nutzen, sie sicher zu machen, Ressourcen vor Überlastung zu schützen usw.
In diesem Blog erstellen wir einen HTTP-Server mit Golang unter Verwendung des Gin-Frameworks, wenden mithilfe von Redis eine Ratenbegrenzungsfunktion auf einen Endpunkt an und speichern die Gesamtzahl der von einer IP an den Server gestellten Anforderungen in einem bestimmten Zeitraum. Und wenn es das von uns festgelegte Limit überschreitet, geben wir eine Fehlermeldung aus.
Falls Sie keine Ahnung haben, was Gin und Redis sind. Gin ist ein in Golang geschriebenes Webframework. Es hilft, einen einfachen und schnellen Server zu erstellen, ohne viel Code schreiben zu müssen. Redis ist ein In-Memory- und Schlüsselwert-Datenspeicher, der als Datenbank oder für Caching-Funktionen verwendet werden kann.
Jetzt fangen wir an.
Um das Projekt zu initialisieren, gehen Sie zu mod init
Dann erstellen wir einen einfachen HTTP-Server mit Gin Framework und wenden dann die Logik zur Ratenbegrenzung an. Sie können den Code unten kopieren. Es ist sehr einfach. Der Server antwortet mit einer Nachricht, wenn wir den Endpunkt /message erreichen.
Nachdem Sie den folgenden Code kopiert haben, führen Sie „go mod Tidy“ aus, um die von uns importierten Pakete automatisch zu installieren.
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/message", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "You can make more requests", }) }) r.Run(":8081") //listen and serve on localhost:8081 }
Wir können den Server ausführen, indem wir go run main.go im Terminal ausführen und diese Meldung im Terminal sehen.
Um es zu testen, können wir zu localhost:8081/message gehen. Wir werden diese Nachricht im Browser sehen.
Jetzt läuft unser Server. Richten wir eine Ratenbegrenzungsfunktion für die /message-Route ein. Wir werden das Paket go-redis/redis_rate verwenden. Dank des Erstellers dieses Pakets müssen wir die Logik für die Handhabung und Überprüfung des Limits nicht von Grund auf neu schreiben. Es wird die ganze schwere Arbeit für uns erledigen.
Unten finden Sie den vollständigen Code nach der Implementierung der Ratenbegrenzungsfunktion. Wir werden jeden Teil davon verstehen. Geben Sie einfach frühzeitig den vollständigen Code an, um Verwirrung zu vermeiden und zu verstehen, wie verschiedene Teile zusammenarbeiten.
Sobald Sie den Code kopiert haben, führen Sie „Mod Tidy“ aus, um alle importierten Pakete zu installieren. Lassen Sie uns nun springen und den Code verstehen (unter dem Codeausschnitt).
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/message", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "You can make more requests", }) }) r.Run(":8081") //listen and serve on localhost:8081 }
Lassen Sie uns zunächst direkt zur Funktion rateLimiter() springen und sie verstehen. Diese Funktion fragt nach einem Argument, das die IP-Adresse der Anfrage ist, die wir über c.ClientIP() in der Hauptfunktion erhalten können. Und wir geben einen Fehler zurück, wenn das Limit erreicht wird, andernfalls behalten wir es bei Null. Der größte Teil des Codes ist Boilerplate-Code, den wir dem offiziellen GitHub-Repo entnommen haben. Die wichtigste Funktionalität, die hier genauer untersucht werden soll, ist die Funktion limiter.Allow(). Addr: Nimmt den URL-Pfadwert für die Redis-Instanz an. Ich verwende Docker, um es lokal auszuführen. Sie können alles verwenden, achten Sie nur darauf, die URL entsprechend zu ersetzen.
package main import ( "context" "errors" "net/http" "github.com/gin-gonic/gin" "github.com/go-redis/redis_rate/v10" "github.com/redis/go-redis/v9" ) func main() { r := gin.Default() r.GET("/message", func(c *gin.Context) { err := rateLimiter(c.ClientIP()) if err != nil { c.JSON(http.StatusTooManyRequests, gin.H{ "message": "you have hit the limit", }) return } c.JSON(http.StatusOK, gin.H{ "message": "You can make more requests", }) }) r.Run(":8081") } func rateLimiter(clientIP string) error { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) limiter := redis_rate.NewLimiter(rdb) res, err := limiter.Allow(ctx, clientIP, redis_rate.PerMinute(10)) if err != nil { panic(err) } if res.Remaining == 0 { return errors.New("Rate") } return nil }
Es werden drei Argumente benötigt, das erste ist ctx, das zweite ist Key, Schlüssel (Schlüssel für einen Wert) für die Redis-Datenbank, und das dritte ist das Limit. Die Funktion speichert also die clientIP-Adresse als Schlüssel und den Standardgrenzwert als Wert und reduziert ihn bei einer Anfrage. Der Grund für diese Struktur liegt darin, dass die Redis-Datenbank eine eindeutige Identifizierung und einen eindeutigen Schlüssel zum Speichern von Schlüssel-Wert-Paar-Daten benötigt und jede IP-Adresse auf ihre eigene Weise einzigartig ist. Aus diesem Grund verwenden wir IP-Adressen anstelle von Benutzernamen. usw. Das dritte Argument redis_rate.PerMinute(10) kann je nach Bedarf geändert werden. Wir können den Grenzwert PerSecond, PerHour usw. festlegen und den Wert in Klammern für die Anzahl festlegen Anfragen können pro Minute/Sekunde/Stunde gestellt werden. In unserem Fall sind es 10 pro Minute. Ja, so einfach ist die Einstellung.
Zuletzt prüfen wir, ob noch ein Restkontingent von not by res.Remaining vorhanden ist. Wenn es Null ist, geben wir einen Fehler mit der Meldung zurück, andernfalls geben wir Null zurück. Sie können beispielsweise auch res.Limit.Rate ausführen, um die Grenzrate usw. zu überprüfen. Sie können herumspielen und tiefer in die Materie eintauchen.
Jetzt kommt die Funktion main():
res, err := limiter.Allow(ctx, clientIP, redis_rate.PerMinute(10))
Alles ist fast gleich. In der /message-Route rufen wir nun jedes Mal, wenn die Route erreicht wird, die Funktion rateLimit() auf, übergeben ihr eine ClientIP-Adresse und speichern den Rückgabewert (Fehler) in der Variablen err. Wenn ein Fehler auftritt, geben wir einen 429 zurück, also http.StatusTooManyRequests, und eine Meldung „message“: „Sie haben das Limit erreicht“. Wenn die Person über ein verbleibendes Limit verfügt und rateLimit() keinen Fehler zurückgibt, funktioniert es wie zuvor normal und bedient die Anfrage.
Das war die ganze Erklärung. Lassen Sie uns nun die Funktionsweise testen. Führen Sie den Server erneut aus, indem Sie denselben Befehl ausführen. Zum ersten Mal sehen wir dieselbe Meldung wie zuvor. Aktualisieren Sie nun Ihren Browser 10 Mal (da wir ein Limit von 10 pro Minute festlegen), und Sie werden die Fehlermeldung im Browser sehen.
Wir können dies auch anhand der Protokolle im Terminal überprüfen. Gin bietet großartiges Logging direkt nach dem Auspacken. Nach einer Minute wird unser Grenzkontingent wiederhergestellt.
Damit bin ich am Ende dieses Blogs angelangt. Ich hoffe, dass Ihnen die Lektüre genauso viel Spaß macht wie mir das Schreiben. Ich freue mich, dass Sie es bis zum Ende geschafft haben – vielen Dank für Ihre Unterstützung. Ich spreche auch regelmäßig über Golang und andere Dinge wie Open Source und Docker auf X (Twitter). Du kannst mich dort vernetzen.
Das obige ist der detaillierte Inhalt vonRatenbegrenzung einer Golang-API mithilfe von Redis. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!