我目前使用的是Redis,版本:3.2.12,作为我的应用程序的缓存:Sping Boot 。我想匹配一个模式列表,然后从Redis中删除它们。我选择使用LUA脚本,并提出了以下脚本。
local cursor='0';
local keysVar = {};
repeat
local scanResult = redis.call('SCAN', cursor, 'MATCH', ARGV[1], 'COUNT', 100);
local keys = scanResult[2];
for i = 1, #keys do
keysVar[i] = keys[i];
end;
cursor = scanResult[1];
until cursor == '0';
redis.replicate_commands()
redis.call('DEL', unpack(keysVar));
return keysVar ;
据我所知,创建SCAN
命令是为了打破KEYS
命令的阻塞,因为它在生产环境中使用时会带来很大的问题。但是,由于我决定使用LUA,Redis保证了脚本的原子执行。在执行脚本时,在一个LUA脚本中使用KEYS
和SCAN
,它们的时间复杂度不是O(N)吗?
那么,使用上面的脚本与使用
return redis.call('DEL', 'defaultKey', unpack(redis.call('KEYS', @keypattern)))
还有一个问题。为什么KEYS
命令被认为是确定性的,当我们假设slave执行带有模式的KEYS
命令时,返回的键数不能改变吗?SCAN
命令是不确定性的原因是,从主机到从主机返回的结果可能不同。KEYS
也不能这样说吗?
既然SCAN
使用游标,那么同一个键怎么可能被多次返回呢?
我正在尝试使用Redis模板删除模式列表。
private void clearCache(List<String> patterns) {
Resource scriptSource = new ClassPathResource("cleanup.lua");
RedisScript<String> redisScript = RedisScript.of(scriptSource, String.class);
patterns.forEach(pattern -> {
redisTemplate.execute(redisScript, Collections.emptyList(), pattern);
});
}
是否有正确/推荐的方法?
1条答案
按热度按时间7uzetpgm1#
在一个LUA脚本中使用KEYS和SCAN,它们的时间复杂度都是O(N)吗?
是的,它们都有O(N)的复杂度。所以你不应该在生产环境中使用它们。
那么,使用上面的脚本与使用...
如果有太多的键,那么带有解压缩
keys
结果的脚本可能会失败。因为,如果我没记错的话,Redis对命令的字节长度有限制。既然SCAN使用了游标,那么同一个键怎么可能被多次返回呢?
因为通常情况下,密钥空间在扫描期间是动态的,例如添加新密钥、旧密钥过期或删除。