Mit der rasanten Entwicklung des Internets und des mobilen Internets ist es zu einem großen Problem geworden, Client-Anfragen an den Server zu beschränken und Serverabstürze zu vermeiden. In tatsächlichen Projekten müssen wir häufig die Anzahl der IP-Anfragen begrenzen, um die Verfügbarkeit der Website sicherzustellen.
Hier stellen wir vor, wie man mit Golang eine IP-Strombegrenzung implementiert. Im Allgemeinen verwenden wir den Token-Bucket-Algorithmus, um eine Strombegrenzung basierend auf der IP-Adresse zu implementieren. Der Token-Bucket-Algorithmus ist ein Flusskontrollalgorithmus, der eine bestimmte Anzahl von Anforderungen innerhalb eines bestimmten Zeitraums passieren lässt und den Anforderungsfluss innerhalb eines bestimmten Zeitraums begrenzt.
Implementierungsdetails
Der Token-Bucket-Algorithmus legt Token mit einer konstanten Rate in den Bucket. Der Token-Bucket hat eine Kapazitätsgrenze, was bedeutet, dass die Anzahl der Token im Bucket die Kapazität nicht überschreitet. Für jede Anfrage wird ein Token aus dem Bucket entfernt. Wenn sich kein Token im Bucket befindet, kann die Anfrage nicht weitergeleitet werden.
Um eine Strombegrenzung basierend auf der IP-Adresse zu implementieren, müssen wir für jede IP-Adresse einen Token-Bucket erstellen. Jeder Token-Bucket hat eine maximale Kapazität und eine konstante Geschwindigkeit. Wenn eine Anfrage eingeht, entfernen wir ein Token aus dem Token-Bucket und lehnen die Anfrage ab, wenn sich kein Token im Bucket befindet.
Auf dieser Grundlage können wir einen aktuellen IP-Limiter definieren:
type IPRateLimiter struct { limiterBuckets map[string]*rate.Limiter mu *sync.Mutex r rate.Limit b int }
wobei limiterBuckets eine Zuordnung ist, die String-IP-Adressen Token-Buckets zuordnet. mu ist ein Mutex, r ist die Rate, mit der der Ratenbegrenzer Token pro Sekunde platziert, und b ist die Kapazität des Token-Buckets.
Um einen Token-Bucket für jede IP-Adresse zu erstellen, definieren wir eine Funktion NewIPRateLimiter:
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter { return &IPRateLimiter{ limiterBuckets: make(map[string]*rate.Limiter), mu: &sync.Mutex{}, r: r, b: b, } } func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter { i.mu.Lock() defer i.mu.Unlock() limiter := rate.NewLimiter(i.r, i.b) i.limiterBuckets[ip] = limiter return limiter }
Die AddIP-Funktion wird verwendet, um einen Token-Bucket für eine IP-Adresse zu erstellen. Wenn für diese IP-Adresse ein Token-Bucket erstellt wurde, wird der vorhandene Token-Bucket zurückgegeben, andernfalls wird ein neuer Token-Bucket erstellt und zurückgegeben.
Schließlich können wir HTTP-Middleware implementieren, um die Anzahl der Anfragen an eine IP-Adresse zu begrenzen:
func (i *IPRateLimiter) Limit(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ip := r.RemoteAddr limiter, ok := i.limiterBuckets[ip] if !ok { limiter = i.AddIP(ip) } if !limiter.Allow() { http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) }
Diese Middleware ermöglicht die Weiterleitung von Anfragen mit einer bestimmten Geschwindigkeit und Kapazität. Wenn die Anzahl der Anfragen die Kapazität überschreitet, wird der HTTP-Fehlercode 429 (Too Many Requests) zurückgegeben.
Der vollständige Code lautet wie folgt:
package main import ( "net/http" "strconv" "sync" "golang.org/x/time/rate" ) type IPRateLimiter struct { limiterBuckets map[string]*rate.Limiter mu *sync.Mutex r rate.Limit b int } func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter { return &IPRateLimiter{ limiterBuckets: make(map[string]*rate.Limiter), mu: &sync.Mutex{}, r: r, b: b, } } func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter { i.mu.Lock() defer i.mu.Unlock() limiter := rate.NewLimiter(i.r, i.b) i.limiterBuckets[ip] = limiter return limiter } func (i *IPRateLimiter) Limit(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ip := r.RemoteAddr limiter, ok := i.limiterBuckets[ip] if !ok { limiter = i.AddIP(ip) } if !limiter.Allow() { http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) } func IndexHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("welcome.")) } func main() { limit := rate.Limit(10) // 速率,每秒放入令牌的数量 capacity := 100 // 容量,桶的大小 ipRateLimiter := NewIPRateLimiter(limit, capacity) http.Handle("/", ipRateLimiter.Limit(http.HandlerFunc(IndexHandler))) err := http.ListenAndServe(":8080", nil) if err != nil { panic(err) } }
In diesem Beispiel erlauben wir 10 Token pro Sekunde und begrenzen die Bucket-Kapazität auf 100. Das bedeutet, dass der Limiter bis zu 10 Anfragen pro Sekunde verarbeiten kann, jedoch fehlschlägt, wenn die Anfragen an dieselbe IP-Adresse 100 erreichen. Gleichzeitig definieren wir einen einfachen Handler, der auf „Willkommen“ antwortet.
Fazit
In diesem Artikel haben wir Golang verwendet, um die IP-Strombegrenzung zu implementieren, indem wir den Token-Bucket-Algorithmus verwendet haben, um die Anforderungsrate jeder IP-Adresse zu begrenzen. Diese Methode kann einen einfachen und effektiven Strombegrenzungsmechanismus implementieren und kann problemlos in Golang implementiert werden. Dies kann eine sehr nützliche Technik sein, wenn Sie hochgradig gleichzeitige Netzwerkanwendungen schreiben.
Das obige ist der detaillierte Inhalt vonGolang implementiert eine IP-Strombegrenzung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!