Ein Artikel, um über die aktuelle Begrenzungsstrategie in Redis zu sprechen
In diesem Artikel erfahren Sie mehr über die Strombegrenzung in Redis und stellen die einfache Strombegrenzungsstrategie und die Trichterstrombegrenzung vor. Ich hoffe, dass er für alle hilfreich ist!
1. Einfache Strombegrenzung
Grundprinzipien
Wenn die Systemverarbeitungskapazität begrenzt ist, wie können ungeplante Anforderungen organisiert werden, um Druck auf das System auszuüben? Schauen wir uns zunächst einige einfache Strategien zur Strombegrenzung an, um Brute-Force-Angriffe zu verhindern. Wenn Sie beispielsweise auf eine IP zugreifen möchten, können Sie alle 5 Sekunden nur 10 Mal darauf zugreifen. Wenn das Limit überschritten wird, wird sie blockiert. [Verwandte Empfehlungen: Redis-Video-Tutorial]
Wie oben gezeigt, wird im Allgemeinen ein Schiebefenster verwendet, um die Anzahl der Besuche innerhalb eines Intervalls zu zählen.
Verwenden Sie zset
, um die Anzahl der IP
-Besuche aufzuzeichnen. Jede IP
wird über key
und score Speichern Sie den aktuellen Zeitstempel, <code>value
wird nur mit Zeitstempel oder UUID implementiertzset
记录 IP
访问次数,每个 IP
通过 key
保存下来,score
保存当前时间戳,value
唯一用时间戳或者UUID来实现
代码实现
public class RedisLimiterTest { private Jedis jedis; public RedisLimiterTest(Jedis jedis) { this.jedis = jedis; } /** * @param ipAddress Ip地址 * @param period 特定的时间内,单位秒 * @param maxCount 最大允许的次数 * @return */ public boolean isIpLimit(String ipAddress, int period, int maxCount) { String key = String.format("ip:%s", ipAddress); // 毫秒时间戳 long currentTimeMillis = System.currentTimeMillis(); Pipeline pipe = jedis.pipelined(); // redis事务,保证原子性 pipe.multi(); // 存放数据,value 和 score 都使用毫秒时间戳 pipe.zadd(key, currentTimeMillis, "" + UUID.randomUUID()); // 移除窗口区间所有的元素 pipe.zremrangeByScore(key, 0, currentTimeMillis - period * 1000); // 获取时间窗口内的行为数量 Response<Long> count = pipe.zcard(key); // 设置 zset 过期时间,避免冷用户持续占用内存,这里宽限1s pipe.expire(key, period + 1); // 提交事务 pipe.exec(); pipe.close(); // 比较数量是否超标 return count.get() > maxCount; } public static void main(String[] args) { Jedis jedis = new Jedis("localhost", 6379); RedisLimiterTest limiter = new RedisLimiterTest(jedis); for (int i = 1; i <= 20; i++) { // 验证IP 10秒钟之内只能访问5次 boolean isLimit = limiter.isIpLimit("222.73.55.22", 10, 5); System.out.println("访问第" + i + "次, 结果:" + (isLimit ? "限制访问" : "允许访问")); } } }
执行结果
访问第1次, 结果:允许访问 访问第2次, 结果:允许访问 访问第3次, 结果:允许访问 访问第4次, 结果:允许访问 访问第5次, 结果:允许访问 访问第6次, 结果:限制访问 访问第7次, 结果:限制访问 ... ...
缺点:要记录时间窗口所有的行为记录,量很大,比如,限定60s内不能超过100万次这种场景,不太适合这样限流,因为会消耗大量的储存空间。
二、漏斗限流
基本原理
- 漏斗的容量是限定的,如果满了,就装不进去了。
- 如果将漏嘴放开,水就会往下流,流走一部分之后,就又可以继续往里面灌水。
- 如果漏嘴流水的速率大于灌水的速率,那么漏斗永远都装不满。
- 如果漏嘴流水速率小于灌水的速率,那么一旦漏斗满了,灌水就需要暂停并等待漏斗腾空。
示例代码
public class FunnelLimiterTest { static class Funnel { int capacity; // 漏斗容量 float leakingRate; // 漏嘴流水速率 int leftQuota; // 漏斗剩余空间 long leakingTs; // 上一次漏水时间 public Funnel(int capacity, float leakingRate) { this.capacity = capacity; this.leakingRate = leakingRate; this.leftQuota = capacity; this.leakingTs = System.currentTimeMillis(); } void makeSpace() { long nowTs = System.currentTimeMillis(); long deltaTs = nowTs - leakingTs; // 距离上一次漏水过去了多久 int deltaQuota = (int) (deltaTs * leakingRate); // 腾出的空间 = 时间*漏水速率 if (deltaQuota < 0) { // 间隔时间太长,整数数字过大溢出 this.leftQuota = capacity; this.leakingTs = nowTs; return; } if (deltaQuota < 1) { // 腾出空间太小 就等下次,最小单位是1 return; } this.leftQuota += deltaQuota; // 漏斗剩余空间 = 漏斗剩余空间 + 腾出的空间 this.leakingTs = nowTs; if (this.leftQuota > this.capacity) { // 剩余空间不得高于容量 this.leftQuota = this.capacity; } } boolean watering(int quota) { makeSpace(); if (this.leftQuota >= quota) { // 判断剩余空间是否足够 this.leftQuota -= quota; return true; } return false; } } // 所有的漏斗 private Map<String, Funnel> funnels = new HashMap<>(); /** * @param capacity 漏斗容量 * @param leakingRate 漏嘴流水速率 quota/s */ public boolean isIpLimit(String ipAddress, int capacity, float leakingRate) { String key = String.format("ip:%s", ipAddress); Funnel funnel = funnels.get(key); if (funnel == null) { funnel = new Funnel(capacity, leakingRate); funnels.put(key, funnel); } return !funnel.watering(1); // 需要1个quota } public static void main(String[] args) throws Exception{ FunnelLimiterTest limiter = new FunnelLimiterTest(); for (int i = 1; i <= 50; i++) { // 每1s执行一次 Thread.sleep(1000); // 漏斗容量是2 ,漏嘴流水速率是0.5每秒, boolean isLimit = limiter.isIpLimit("222.73.55.22", 2, (float)0.5/1000); System.out.println("访问第" + i + "次, 结果:" + (isLimit ? "限制访问" : "允许访问")); } } }
执行结果
访问第1次, 结果:允许访问 # 第1次,容量剩余2,执行后1 访问第2次, 结果:允许访问 # 第2次,容量剩余1,执行后0 访问第3次, 结果:允许访问 # 第3次,由于过了2s, 漏斗流水剩余1个空间,所以容量剩余1,执行后0 访问第4次, 结果:限制访问 # 第4次,过了1s, 剩余空间小于1, 容量剩余0 访问第5次, 结果:允许访问 # 第5次,由于过了2s, 漏斗流水剩余1个空间,所以容量剩余1,执行后0 访问第6次, 结果:限制访问 # 以此类推... 访问第7次, 结果:允许访问 访问第8次, 结果:限制访问 访问第9次, 结果:允许访问 访问第10次, 结果:限制访问
- 我们观察
Funnel
对象的几个字段,我们发现可以将Funnel
对象的内容按字段存储到一个hash
结构中,灌水的时候将hash
结构的字段取出来进行逻辑运算后,再将新值回填到hash
结构中就完成了一次行为频度的检测。 - 但是有个问题,我们无法保证整个过程的原子性。从
hash
结构中取值,然后在内存里运算,再回填到hash
结构,这三个过程无法原子化,意味着需要进行适当的加锁控制。而一旦加锁,就意味着会有加锁失败,加锁失败就需要选择重试或者放弃。 - 如果重试的话,就会导致性能下降。如果放弃的话,就会影响用户体验。同时,代码的复杂度也跟着升高很多。这真是个艰难的选择,我们该如何解决这个问题呢?
Redis-Cell
救星来了!
Redis-Cell
Redis 4.0 提供了一个限流 Redis 模块,它叫 redis-cell
。该模块也使用了漏斗算法,并提供了原子的限流指令。
该模块只有1条指令cl.throttle
,它的参数和返回值都略显复杂,接下来让我们来看看这个指令具体该如何使用。
> cl.throttle key:xxx 15 30 60 1
15
: 15 capacity 这是漏斗容量30 60
: 30 operations / 60 seconds 这是漏水速率1
: need 1 quota (可选参数,默认值也是1)
> cl.throttle laoqian:reply 15 30 60 1) (integer) 0 # 0 表示允许,1表示拒绝 2) (integer) 15 # 漏斗容量capacity 3) (integer) 14 # 漏斗剩余空间left_quota 4) (integer) -1 # 如果拒绝了,需要多长时间后再试(漏斗有空间了,单位秒) 5) (integer) 2 # 多长时间后,漏斗完全空出来(left_quota==capacity,单位秒)
在执行限流指令时,如果被拒绝了,就需要丢弃或重试。cl.throttle
指令考虑的非常周到,连重试时间都帮你算好了,直接取返回结果数组的第四个值进行 sleep
Code-Implementierung
Ausführungsergebnisse🎜🎜rrreee🎜Nachteile: Es ist notwendig, alle Verhaltensdatensätze im Zeitfenster aufzuzeichnen, was beispielsweise sehr groß ist. Das Szenario, die Häufigkeit auf nicht mehr als 1 Million Mal in 60 Sekunden zu begrenzen, ist dafür nicht geeignet Strombegrenzung, da dadurch viel Speicherplatz verbraucht wird. 🎜2. Strombegrenzung des Trichters 🎜🎜Grundprinzip🎜🎜
- Die Kapazität des Der Trichter ist begrenzt. Wenn er voll ist, passt er nicht hinein.
- Wenn Sie den Auslauf loslassen, fließt das Wasser nach unten. Nachdem ein Teil davon abfließt, können Sie ihn weiter mit Wasser füllen.
- Wenn die Durchflussrate des Wassers aus dem Auslauf größer ist als die Wasserfüllrate, wird der Trichter nie voll sein.
- Wenn die Durchflussrate des Trichters geringer ist als die Füllrate, muss der Füllvorgang angehalten werden, sobald der Trichter voll ist, und warten, bis der Trichter leer ist.
🎜Beispielcode🎜🎜rrreee🎜🎜Ausführungsergebnisse🎜🎜rrreee
- Wir beobachten den
Trichter
Bei mehreren Feldern haben wir festgestellt, dass der Inhalt des Funnel
-Objekts feldweise in einer hash
-Struktur gespeichert werden kann Nachdem die Felder für logische Operationen entnommen wurden, werden die neuen Werte in die hash
-Struktur eingefügt, um eine Verhaltenshäufigkeitserkennung abzuschließen.
- Aber es gibt ein Problem: Wir können die Atomizität des gesamten Prozesses nicht garantieren. Holen Sie sich den Wert aus der
hash
-Struktur, verarbeiten Sie ihn dann im Speicher und füllen Sie ihn dann in die hash
-Struktur ein. Diese drei Prozesse können nicht atomar sein, was bedeutet, dass eine entsprechende Sperre erforderlich ist Kontrolle ist erforderlich. Sobald die Sperre gesperrt ist, liegt ein Sperrfehler vor. Wenn die Sperre fehlschlägt, müssen Sie entscheiden, ob Sie es erneut versuchen oder aufgeben möchten.
- Wenn Sie es erneut versuchen, verringert sich die Leistung. Wenn Sie aufgeben, wirkt sich dies auf die Benutzererfahrung aus. Gleichzeitig hat auch die Komplexität des Codes stark zugenommen. Das ist eine wirklich schwierige Entscheidung. Wie lösen wir dieses Problem?
Redis-Cell
Der Retter ist da!
🎜Redis-Cell🎜🎜🎜Redis 4.0 bietet ein aktuell begrenztes Redis-Modul namens redis-cell
. Dieses Modul verwendet auch den Trichteralgorithmus und bietet Anweisungen zur atomaren Strombegrenzung.
Dieses Modul hat nur eine Anweisung cl.throttle
und seine Parameter und Rückgabewerte sind etwas kompliziert. Schauen wir uns als Nächstes an, wie diese Anweisung verwendet wird. 🎜rrreee
-
15
: 15 Kapazität Das ist die Trichterkapazität
-
30 60
: 30 Betätigungen / 60 Sekunden Das ist das Wasser Leckrate
-
1
: benötigt 1 Kontingent (optionaler Parameter, der Standardwert ist ebenfalls 1)
rrreee🎜Wenn der Strombegrenzungsbefehl ausgeführt wird, wenn Es wird abgelehnt. Sie müssen es verwerfen oder es erneut versuchen. Die Anweisung cl.throttle
ist sehr durchdacht und berechnet sogar die Wiederholungszeit für Sie. Nehmen Sie einfach den vierten Wert des zurückgegebenen Ergebnisarrays und führen Sie sleep
aus. Wenn Sie den Thread nicht blockieren möchten, können Sie es auch mit einer asynchronen geplanten Aufgabe erneut versuchen. 🎜🎜Weitere Kenntnisse zum Thema Programmierung finden Sie unter: 🎜Programmiervideos🎜! ! 🎜
- Die Kapazität des Der Trichter ist begrenzt. Wenn er voll ist, passt er nicht hinein.
- Wenn Sie den Auslauf loslassen, fließt das Wasser nach unten. Nachdem ein Teil davon abfließt, können Sie ihn weiter mit Wasser füllen.
- Wenn die Durchflussrate des Wassers aus dem Auslauf größer ist als die Wasserfüllrate, wird der Trichter nie voll sein.
- Wenn die Durchflussrate des Trichters geringer ist als die Füllrate, muss der Füllvorgang angehalten werden, sobald der Trichter voll ist, und warten, bis der Trichter leer ist.
🎜Beispielcode🎜🎜rrreee🎜🎜Ausführungsergebnisse🎜🎜rrreee
- Wir beobachten den
Trichter
Bei mehreren Feldern haben wir festgestellt, dass der Inhalt des Funnel
-Objekts feldweise in einer hash
-Struktur gespeichert werden kann Nachdem die Felder für logische Operationen entnommen wurden, werden die neuen Werte in die hash
-Struktur eingefügt, um eine Verhaltenshäufigkeitserkennung abzuschließen.
- Aber es gibt ein Problem: Wir können die Atomizität des gesamten Prozesses nicht garantieren. Holen Sie sich den Wert aus der
hash
-Struktur, verarbeiten Sie ihn dann im Speicher und füllen Sie ihn dann in die hash
-Struktur ein. Diese drei Prozesse können nicht atomar sein, was bedeutet, dass eine entsprechende Sperre erforderlich ist Kontrolle ist erforderlich. Sobald die Sperre gesperrt ist, liegt ein Sperrfehler vor. Wenn die Sperre fehlschlägt, müssen Sie entscheiden, ob Sie es erneut versuchen oder aufgeben möchten.
- Wenn Sie es erneut versuchen, verringert sich die Leistung. Wenn Sie aufgeben, wirkt sich dies auf die Benutzererfahrung aus. Gleichzeitig hat auch die Komplexität des Codes stark zugenommen. Das ist eine wirklich schwierige Entscheidung. Wie lösen wir dieses Problem?
Redis-Cell
Der Retter ist da!
🎜Redis-Cell🎜🎜🎜Redis 4.0 bietet ein aktuell begrenztes Redis-Modul namens redis-cell
. Dieses Modul verwendet auch den Trichteralgorithmus und bietet Anweisungen zur atomaren Strombegrenzung.
Dieses Modul hat nur eine Anweisung cl.throttle
und seine Parameter und Rückgabewerte sind etwas kompliziert. Schauen wir uns als Nächstes an, wie diese Anweisung verwendet wird. 🎜rrreee
-
15
: 15 Kapazität Das ist die Trichterkapazität
-
30 60
: 30 Betätigungen / 60 Sekunden Das ist das Wasser Leckrate
-
1
: benötigt 1 Kontingent (optionaler Parameter, der Standardwert ist ebenfalls 1)
rrreee🎜Wenn der Strombegrenzungsbefehl ausgeführt wird, wenn Es wird abgelehnt. Sie müssen es verwerfen oder es erneut versuchen. Die Anweisung cl.throttle
ist sehr durchdacht und berechnet sogar die Wiederholungszeit für Sie. Nehmen Sie einfach den vierten Wert des zurückgegebenen Ergebnisarrays und führen Sie sleep
aus. Wenn Sie den Thread nicht blockieren möchten, können Sie es auch mit einer asynchronen geplanten Aufgabe erneut versuchen. 🎜🎜Weitere Kenntnisse zum Thema Programmierung finden Sie unter: 🎜Programmiervideos🎜! ! 🎜
Trichter
Bei mehreren Feldern haben wir festgestellt, dass der Inhalt des Funnel
-Objekts feldweise in einer hash
-Struktur gespeichert werden kann Nachdem die Felder für logische Operationen entnommen wurden, werden die neuen Werte in die hash
-Struktur eingefügt, um eine Verhaltenshäufigkeitserkennung abzuschließen. hash
-Struktur, verarbeiten Sie ihn dann im Speicher und füllen Sie ihn dann in die hash
-Struktur ein. Diese drei Prozesse können nicht atomar sein, was bedeutet, dass eine entsprechende Sperre erforderlich ist Kontrolle ist erforderlich. Sobald die Sperre gesperrt ist, liegt ein Sperrfehler vor. Wenn die Sperre fehlschlägt, müssen Sie entscheiden, ob Sie es erneut versuchen oder aufgeben möchten. Redis-Cell
Der Retter ist da! redis-cell
. Dieses Modul verwendet auch den Trichteralgorithmus und bietet Anweisungen zur atomaren Strombegrenzung.
Dieses Modul hat nur eine Anweisung cl.throttle
und seine Parameter und Rückgabewerte sind etwas kompliziert. Schauen wir uns als Nächstes an, wie diese Anweisung verwendet wird. 🎜rrreee-
15
: 15 Kapazität Das ist die Trichterkapazität -
30 60
: 30 Betätigungen / 60 Sekunden Das ist das Wasser Leckrate -
1
: benötigt 1 Kontingent (optionaler Parameter, der Standardwert ist ebenfalls 1)
cl.throttle
ist sehr durchdacht und berechnet sogar die Wiederholungszeit für Sie. Nehmen Sie einfach den vierten Wert des zurückgegebenen Ergebnisarrays und führen Sie sleep
aus. Wenn Sie den Thread nicht blockieren möchten, können Sie es auch mit einer asynchronen geplanten Aufgabe erneut versuchen. 🎜🎜Weitere Kenntnisse zum Thema Programmierung finden Sie unter: 🎜Programmiervideos🎜! ! 🎜Das obige ist der detaillierte Inhalt vonEin Artikel, um über die aktuelle Begrenzungsstrategie in Redis zu sprechen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

1. Starten Sie das Menü [Start], geben Sie [cmd] ein, klicken Sie mit der rechten Maustaste auf [Eingabeaufforderung] und wählen Sie Als [Administrator] ausführen. 2. Geben Sie nacheinander die folgenden Befehle ein (kopieren und fügen Sie sie sorgfältig ein): SCconfigwuauservstart=auto, drücken Sie die Eingabetaste. SCconfigbitsstart=auto, drücken Sie die Eingabetaste. SCconfigcryptsvcstart=auto, drücken Sie die Eingabetaste. SCconfigtrustedinstallerstart=auto, drücken Sie die Eingabetaste. SCconfigwuauservtype=share, drücken Sie die Eingabetaste. netstopwuauserv, drücken Sie die Eingabetaste für netstopcryptS

Engpässe bei PHP-Funktionen führen zu geringer Leistung, was durch die folgenden Schritte behoben werden kann: Suchen Sie die Engpassfunktion und verwenden Sie Tools zur Leistungsanalyse. Ergebnisse zwischenspeichern, um Neuberechnungen zu reduzieren. Verarbeiten Sie Aufgaben parallel, um die Ausführungseffizienz zu verbessern. Optimieren Sie die Zeichenfolgenverkettung und verwenden Sie stattdessen integrierte Funktionen. Verwenden Sie integrierte Funktionen anstelle benutzerdefinierter Funktionen.

Die Caching-Strategie in GolangAPI kann die Leistung verbessern und die Serverlast reduzieren. Häufig verwendete Strategien sind: LRU, LFU, FIFO und TTL. Zu den Optimierungstechniken gehören die Auswahl geeigneter Cache-Speicher, hierarchisches Caching, Invalidierungsmanagement sowie Überwachung und Optimierung. Im praktischen Fall wird der LRU-Cache verwendet, um die API zum Abrufen von Benutzerinformationen aus der Datenbank zu optimieren. Andernfalls kann der Cache nach dem Abrufen aus der Datenbank aktualisiert werden.

Es gibt Leistungsunterschiede zwischen Erlang und Go. Erlang zeichnet sich durch Parallelität aus, während Go einen höheren Durchsatz und eine schnellere Netzwerkleistung bietet. Erlang eignet sich für Systeme, die eine hohe Parallelität erfordern, während Go für Systeme geeignet ist, die einen hohen Durchsatz und eine geringe Latenz erfordern.

In der PHP-Entwicklung verbessert der Caching-Mechanismus die Leistung, indem er häufig aufgerufene Daten vorübergehend im Speicher oder auf der Festplatte speichert und so die Anzahl der Datenbankzugriffe reduziert. Zu den Cache-Typen gehören hauptsächlich Speicher-, Datei- und Datenbank-Cache. In PHP können Sie integrierte Funktionen oder Bibliotheken von Drittanbietern verwenden, um Caching zu implementieren, wie zum Beispiel Cache_get() und Memcache. Zu den gängigen praktischen Anwendungen gehören das Zwischenspeichern von Datenbankabfrageergebnissen zur Optimierung der Abfrageleistung und das Zwischenspeichern von Seitenausgaben zur Beschleunigung des Renderings. Der Caching-Mechanismus verbessert effektiv die Reaktionsgeschwindigkeit der Website, verbessert das Benutzererlebnis und reduziert die Serverlast.

Durch die Verwendung des Redis-Cache kann die Leistung des PHP-Array-Pagings erheblich optimiert werden. Dies kann durch die folgenden Schritte erreicht werden: Installieren Sie den Redis-Client. Stellen Sie eine Verbindung zum Redis-Server her. Erstellen Sie Cache-Daten und speichern Sie jede Datenseite in einem Redis-Hash mit dem Schlüssel „page:{page_number}“. Rufen Sie Daten aus dem Cache ab und vermeiden Sie teure Vorgänge auf großen Arrays.

Zuerst müssen Sie die Systemsprache auf die Anzeige in vereinfachtem Chinesisch einstellen und neu starten. Wenn Sie die Anzeigesprache zuvor auf vereinfachtes Chinesisch geändert haben, können Sie diesen Schritt natürlich einfach überspringen. Beginnen Sie als Nächstes mit dem Betrieb der Registrierung regedit.exe, navigieren Sie direkt zu HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlNlsLanguage in der linken Navigationsleiste oder der oberen Adressleiste und ändern Sie dann den InstallLanguage-Schlüsselwert und den Standardschlüsselwert auf 0804 (wenn Sie ihn in Englisch ändern möchten). us, Sie müssen zunächst die Anzeigesprache des Systems auf en-us einstellen, das System neu starten und dann alles auf 0409 ändern) Sie müssen das System an dieser Stelle neu starten.

Ja, Navicat kann eine Verbindung zu Redis herstellen, wodurch Benutzer Schlüssel verwalten, Werte anzeigen, Befehle ausführen, Aktivitäten überwachen und Probleme diagnostizieren können. Um eine Verbindung zu Redis herzustellen, wählen Sie in Navicat den Verbindungstyp „Redis“ und geben Sie die Serverdetails ein.
