1. Einleitung
Strombegrenzungen sind bei der serverseitigen Entwicklung keine Seltenheit. Das erste, was mir in den Sinn kommt, ist Taobao 双11
, 12306
die Szene, in der zu Neujahr Zugtickets gekauft werden, wenn man nach Hause zurückkehrt usw.
Hier ist ein einfaches Geschäftsszenario: Der Benutzer meldet sich mit seinem Konto und Passwort an. Um zu verhindern, dass Schadprogramme versuchen, Passwörter mit Brute-Force zu knacken und häufig Anmeldeanfragen aufrufen, können eine Reihe von Schutzmaßnahmen hinzugefügt werden, wie z : Hinzufügen einer Bestätigungscode-Verifizierung, die innerhalb eines festgelegten Zeitraums überprüft werden kann. Die Anzahl der Versuche der fehlerhaften Anfrage usw.
2. Gehen Sie zur Umsetzung
Verwenden Sie go-cache
Open-Source-Warehouses für die Cache-Steuerung.
package main
import (
"fmt"
"github.com/patrickmn/go-cache"
"time"
)
// 使用
func main() {
// 设置一分钟内可以用户a可以尝试10次
c := NewCache(10, time.Minute, time.Second)
key := "a"
go func() {
ticker := time.NewTicker(time.Millisecond * 200)
for {
select {
case <-ticker.C:
fmt.Println("add")
c.Add(key)
}
}
}()
for {
if c.Limit(key) {
fmt.Println("end")
return
}
}
}
type Cache struct {
c *cache.Cache
countLimit int
}
// cleanupInterval 定时清理缓存的时间
func NewCache(countLimit int, timeLimit, cleanupInterval time.Duration) *Cache {
res := new(Cache)
res.c = cache.New(timeLimit, cleanupInterval)
res.countLimit = countLimit
return res
}
func (this *Cache) Limit(key string) bool {
count, ok := this.c.Get(key)
if !ok {
return false
}
curCount := count.(int)
if curCount >= this.countLimit {
return true
}
return false
}
func (this *Cache) Add(key string) {
count, expiration, ok := this.c.GetWithExpiration(key)
if !ok {
this.c.SetDefault(key, 1)
return
}
// 这里的过期时间重新算一下
duration := expiration.Sub(time.Now())
if duration <= 0 {
return
}
curCount := count.(int)
this.c.Set(key, curCount+1, duration)
return
}
Der obige Code wird 10
mal ausgegeben add
und end
beendet dann das Programm.
3. Strombegrenzungsstrategie
Es gibt viele aktuelle Begrenzungsstrategien. Hier sind einige gängige. Die Auswahl sollte auf der tatsächlichen Situation basieren.
3.1 Strombegrenzung für festes Zeitfenster
Es ist sehr rau. Wenn sich innerhalb von zwei Zeitfenstern der vorherige Burst-Verkehr am Ende und der nächste Burst-Verkehr an der Spitze befindet, kann es immer noch zu einer Systemlähmung kommen.
3.2 Gleitendes Zeitfenster
Eine Verbesserung des Algorithmus für feste Zeitfenster. Nachdem der Verkehr durch den Algorithmus für gleitende Zeitfenster geformt wurde, kann garantiert werden, dass die maximal zulässige Flussgrenze in keinem Zeitfenster überschritten wird. Die Flusskurve wird glatter, was teilweise möglich ist Lösen Sie das oben genannte Problem. Das erwähnte kritische Burst-Traffic-Problem.
3.3 Token-Bucket
- Die Schnittstelle begrenzt die maximale Anzahl an Zugriffen innerhalb von t Sekunden auf n, dann wird alle t/n Sekunden ein Token in den Bucket gelegt;
- Im Bucket können maximal b Token gespeichert werden. Wenn der Token-Bucket beim Eintreffen des Tokens voll ist, wird der Token verworfen;
- Die Schnittstellenanforderung ruft zunächst das Token aus dem Token-Bucket ab. Wenn das Token abgerufen wird, wird die Schnittstellenanforderung verarbeitet. Wenn das Token nicht abgerufen werden kann, wird eine Strombegrenzung durchgeführt.
Token werden mit einer konstanten Rate generiert, bis der maximale Wert des Buckets erreicht ist. Von jeder Anfrage wird ein Token abgezogen und alle Token, die nicht abgerufen werden können, werden verworfen.
3.4 Undichter Eimer
Es wird erfasst, wie viel insgesamt untergebracht werden kann und Ein- und Ausgänge erfasst. Sobald der Eimer voll ist, darf er nicht mehr reingelassen werden.
4. So konfigurieren Sie sinnvolle Strombegrenzungsregeln
Strombegrenzungsregeln bestehen aus drei Teilen: Zeitgranularität, Schnittstellengranularität und maximaler Strombegrenzungswert.
Strombegrenzungsanpassung, Hot-Update (Strombegrenzung ein-/ausschalten, Strombegrenzungsregeln anpassen, Strombegrenzungsalgorithmus ersetzen).
5. Zusammenfassung
Dieser Artikel verwendet hauptsächlich ein Unternehmen, um die Strombegrenzung (festes Zeitfenster) kurz zu beschreiben, und enthält eine go
Version der Implementierung.
Es gibt viele Möglichkeiten, den Strom zu begrenzen, aber Sie müssen immer noch den für Ihr Unternehmen am besten geeigneten Weg finden. Die Schwierigkeit liegt nicht in der Implementierung, sondern darin, wie man den Strom begrenzt und wie man ihn gestaltet.
6. Referenz
Design und Überlegungen zu aktuellen Einschränkungen der InfoQ-Microservice-Schnittstelle
2022/10/18
erneuern
Add
Methoden und Limit
Methoden werden zusammengeführt.
package main
import (
"fmt"
"github.com/patrickmn/go-cache"
"time"
)
func main() {
c := NewCache(10, time.Minute, time.Minute)
key := "a"
ticker := time.NewTicker(time.Millisecond * 200)
i := 0
for {
select {
case <-ticker.C:
i++
if c.Limit1(key) {
fmt.Println("end:", i)
return
}
}
}
}
func (this *Cache) Limit1(key string) bool {
count, expiration, ok := this.c.GetWithExpiration(key)
if !ok {
this.c.SetDefault(key, 1)
return false
}
duration := expiration.Sub(time.Now())
if duration <= 0 {
// 过期了重新设置值
this.c.SetDefault(key, 1)
fmt.Println("过期了")
return false
}
curCount := count.(int)
if curCount >= this.countLimit {
return true
}
this.c.Set(key, curCount+1, duration)
return false
}
Ausgabeergebnis:end:11