Maison >base de données >Redis >Comment Redis peut-il implémenter la limitation de courant ?
Objectif :
Atteindre la limite de fréquence d'accès
Atteindre le $ip des visiteurs dans une certaine limite Vous ne pouvez accéder à $limit times que dans le délai $time
(Partage de vidéos d'apprentissage : tutoriel vidéo Redis)
Implémentation sans script
private boolean accessLimit(String ip, int limit, int time, Jedis jedis) { boolean result = true; String key = "rate.limit:" + ip; if (jedis.exists(key)) { long afterValue = jedis.incr(key); if (afterValue > limit) { result = false; } } else { Transaction transaction = jedis.multi(); transaction.incr(key); transaction.expire(key, time); transaction.exec(); } return result; }
Le code ci-dessus a deux défauts
Une condition de concurrence critique peut survenir : la solution est d'utiliser WATCH pour surveiller les changements dans rate.limit:$IP, mais c'est plus gênant ; Le code ci-dessus n'utilise pas de pipeline. Dans ce cas, jusqu'à 5 instructions doivent être demandées à Redis, ce qui est trop important à transmettre
Implémentation du script Lua
Redis autorise les scripts Lua. à transférer sur le serveur Redis pour exécution, et peut être appelé dans le script La plupart des commandes Redis, et Redis garantit l'atomicité des scripts :
Vous devez d'abord préparer le code Lua : script.lua
-- -- Created by IntelliJ IDEA. -- User: jifang -- Date: 16/8/24 -- Time: 下午6:11 -- local key = "rate.limit:" .. KEYS[1] local limit = tonumber(ARGV[1]) local expire_time = ARGV[2] local is_exists = redis.call("EXISTS", key) if is_exists == 1 then if redis.call("INCR", key) > limit then return 0 else return 1 end else redis.call("SET", key, 1) redis.call("EXPIRE", key, expire_time) return 1 end
Java
private boolean accessLimit(String ip, int limit, int timeout, Jedis connection) throws IOException { List<String> keys = Collections.singletonList(ip); List<String> argv = Arrays.asList(String.valueOf(limit), String.valueOf(timeout)); return 1 == (long) connection.eval(loadScriptString("script.lua"), keys, argv); } // 加载Lua代码 private String loadScriptString(String fileName) throws IOException { Reader reader = new InputStreamReader(Client.class.getClassLoader().getResourceAsStream(fileName)); return CharStreams.toString(reader); }
Lua Embed Redis Avantages :
Réduisez la surcharge du réseau : le code qui n'utilise pas Lua doit envoyer plusieurs requêtes à Redis, mais le script doit seulement être envoyé une seule fois, réduisant la transmission réseau ; opérations atomiques : Redis exécute l'intégralité du script de manière atomique, pas besoin de s'inquiéter. La concurrence signifie qu'il n'y a pas besoin de réutilisation : le script sera enregistré de manière permanente dans Redis et les autres clients pourront continuer à l'utiliser ; .
Recommandations associées : Tutoriel sur la base de données Redis
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!