Lua腳本
Redis從 2.6.0 版本開始內置 Lua 解釋器,可以使用 EVAL 命令對 Lua 腳本進行求值。腳本是lua函數體內的代碼,而不能是包括function關鍵字及大括號。腳本會以原子方式執行,當腳本運行時,其他任何客戶端都不能執行命令,因此,腳本中代碼不應該包含耗時操作。
語法:EVAL script numkeys key [key …] arg [arg …]
。例如:
> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"
其中 "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}"
是被求值的 Lua 腳本,數字 2
指定了鍵名參數的數量, key1
和 key2
是鍵名參數,分別使用 KEYS[1]
和 KEYS[2]
訪問,而最後的 first
和 second
則是附加參數,可以通過 ARGV[1]
和 ARGV[2]
訪問它們。在腳本中調用Redis命令:
> eval "return redis.call('set',KEYS[1],'bar')" 1 foo
OK
在spring data redis中使用
實現一個簡單的計數限流器。
@Configuration
public class RedisConfiguration {
@Bean(name = "simpleRateLimitScript")
public RedisScript<Boolean> script() {
ClassPathResource resource = new ClassPathResource("META-INF/scripts/simple_rate_limiter.lua");
return RedisScript.of(resource, Boolean.class);
}
}
-- 在一段時間內(exp,秒),對某一操作(key),限制允許執行多少次(limit)。
local key = KEYS[1]
local limit = tonumber(KEYS[2])
local exp = tonumber(KEYS[3])
local currentLimit = tonumber(redis.call('GET', key) or 0)
if currentLimit + 1 > limit then
return true
else
redis.call("INCR", key)
redis.call("EXPIRE", key, exp)
return false
end
private static final int MAX = 5;
private static final int EXP_SECONDS = 10 * 60;
public Boolean limit(String key) {
List<String> keys = new ArrayList<>();
keys.add("limit:" + key);
keys.add(String.valueOf(MAX));
keys.add(String.valueOf(EXP_SECONDS));
return stringRedisTemplate.execute(countLimitScript, keys);
}