Empfohlenes Lernen: Redis-Video-Tutorial
Wenn wir die verteilte Sperre von Redis verwenden, weiß jeder, dass wir uns auf die Setnx-Anweisung in CAS (Vergleichen und Tauschen) verlassen. Die Ablaufpraxis (expire) wird für den angegebenen Schlüssel gleichzeitig festgelegt. Unser Hauptzweck der aktuellen Begrenzung besteht darin, nur N-Anfragen den Zugriff auf mein Codeprogramm innerhalb einer Zeiteinheit zu ermöglichen. Wenn Sie sich also auf setnx verlassen, können Sie diese Funktion problemlos erreichen.
Wenn wir beispielsweise 20 Anfragen innerhalb von 10 Sekunden begrenzen müssen, können wir die Ablaufzeit auf 10 setzen, wenn die Anzahl der angeforderten Setnx 20 erreicht, wird der aktuelle Begrenzungseffekt erreicht. Der Code ist relativ einfach und wird nicht angezeigt.
Natürlich hat dieser Ansatz viele Nachteile. Wenn wir beispielsweise 1-10 Sekunden zählen, ist es unmöglich, 2-11 Sekunden zu zählen. Wenn wir M Anfragen innerhalb von N Sekunden zählen müssen, müssen wir N behalten in unserem Redis Key und anderen Problemen.
In der spezifischen Implementierung können Sie die Verwendung des Interceptors HandlerInterceptor in Betracht ziehen:
public class RequestCountInterceptor implements HandlerInterceptor { private LimitPolicy limitPolicy; public RequestCountInterceptor(LimitPolicy limitPolicy) { this.limitPolicy = limitPolicy; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!limitPolicy.canDo()) { return false; } return true; } }
Gleichzeitig fügen Sie eine Konfiguration hinzu LimitConfiguration:
@Configuration public class LimitConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestCountInterceptor(new RedisLimit1())).addPathPatterns("/my/increase"); } }
Auf diese Weise wird jedes Mal, bevor die /my/increase-Anforderung den Controller erreicht, der Fluss erhöht ist gemäß der Richtlinie RedisLimit1 begrenzt. Der Code des ursprünglichen Controllers muss nicht geändert werden:
@RestController @RequestMapping("my") public class MyController { int i = 0; @RequestMapping("/increase") public int increase() { return i++; } }
Der spezifische Strombegrenzungslogikcode befindet sich in der RedisLimit1-Klasse:
/** * 方法一:基于Redis的setnx的操作 */ public class RedisLimit1 extends LimitPolicy { static { setNxExpire(); } private static boolean setNxExpire() { SetParams setParams = new SetParams(); setParams.nx(); setParams.px(TIME); String result = jedis.set(KEY, COUNT + "", setParams); if (SUCCESS.equals(result)) { return true; } return false; } @Override public boolean canDo() { if (setNxExpire()) { //设置成功,说明原先不存在,成功设置为COUNT return true; } else { //设置失败,说明已经存在,直接减1,并且返回 return jedis.decrBy(KEY, 1) > 0; } } } public abstract class LimitPolicy { public static final int COUNT = 10; //10 request public static final int TIME= 10*1000 ; // 10s public static final String SUCCESS = "OK"; static Jedis jedis = new Jedis(); abstract boolean canDo(); }
Ein auf diese Weise erzielter Effekt ist maximal 10 Anfragen pro Sekunde.
Tatsächlich ist das Schiebefenster das Wichtigste bei der Strombegrenzung. Oben wurde auch erwähnt, wie aus 1-10 2-11 wird. Tatsächlich sind sowohl der Startwert als auch der Endwert jeweils +1.
Wenn wir die Listendatenstruktur von Redis verwenden, können wir diese Funktion einfach implementieren.
Wir können die Anfrage in einem Zset-Array erstellen. Wenn jede Anfrage eingeht, bleibt der Wert eindeutig und kann mithilfe der UUID generiert werden, während die Bewertung möglich ist wird anhand der aktuellen Zeitstempeldarstellung generiert, da wir mithilfe des Scores die Anzahl der Anfragen innerhalb des aktuellen Zeitstempels berechnen können. Die zset-Datenstruktur stellt auch die zrange-Methode bereit, sodass wir leicht ermitteln können, wie viele Anforderungen es innerhalb von zwei Zeitstempeln gibt. Der Nachteil besteht darin, dass die Datenstruktur von zset immer größer wird. Die Implementierungsmethode ist relativ einfach.
Methode 3: Redis-basierter Token-Bucket-Algorithmus
Konfigurieren Sie zunächst eine geplante Aufgabe und fügen Sie jede Sekunde ein Token über die rpush-Methode der Redis-Liste ein:
/** * 方法二:基于Redis的数据结构zset */ public class RedisLimit2 extends LimitPolicy { public static final String KEY2 = "LIMIT2"; @Override public boolean canDo() { Long currentTime = new Date().getTime(); System.out.println(currentTime); if (jedis.zcard(KEY2) > 0) { // 这里不能用get判断,会报错:WRONGTYPE Operation against a key holding the wrong kind of value Integer count = jedis.zrangeByScore(KEY2, currentTime - TIME, currentTime).size(); // 注意这里使用zrangeByScore,以时间作为score。zrange key start stop 命令的start和stop是序号。 System.out.println(count); if (count != null && count > COUNT) { return false; } } jedis.zadd(KEY2, Double.valueOf(currentTime), UUID.randomUUID().toString()); return true; } }
Wenn der Strom begrenzt ist, erhalten Sie das entsprechende Token von Redis über die lpop-Methode der Liste , die Anfrage kann ausgeführt werden:
@Configuration //1.主要用于标记配置类,兼备Component的效果。 @EnableScheduling // 2.开启定时任务 public class SaticScheduleTask { //3.添加定时任务 @Scheduled(fixedRate = 1000) private void configureTasks() { LimitPolicy.jedis.rpush("LIMIT3", UUID.randomUUID().toString()); } }
Empfohlenes Lernen:
Redis-Video-TutorialDas obige ist der detaillierte Inhalt vonDrei Möglichkeiten zur Implementierung eines Strombegrenzers in Redis (Zusammenfassungsfreigabe). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!