Purpose:
Realize access frequency limit
Realize visitor $ip within a certain limit You can only access $limit times within time $time
(Learning video sharing: redis video tutorial)
Non-script implementation
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; }
The above code has two flaws
Racing conditions may occur: The solution is to use WATCH to monitor changes in rate.limit:$IP, but it is more troublesome; the above code does not use pipeline In this case, up to 5 instructions need to be requested from Redis, which is too much to transmit.
Lua script implementation
Redis allows Lua scripts to be transferred to the Redis server for execution, and can be called within the script Most Redis commands, and Redis guarantees the atomicity of scripts:
First you need to prepare Lua code: 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 embedded Redis advantages:
Reduce network overhead: Code that does not use Lua needs to send multiple requests to Redis, but the script only needs to be sent once, reducing network transmission; Atomic operations: Redis executes the entire script as an atomic, no need to worry Concurrency means there is no need for transactions; reuse: the script will be permanently saved in Redis and other clients can continue to use it.
Related recommendations: redis database tutorial
The above is the detailed content of How can redis implement current limiting?. For more information, please follow other related articles on the PHP Chinese website!