redis 在LUA脚本中使用KEYS和SCAN有什么区别?

bvjveswy  于 2022-11-21  发布在  Redis
关注(0)|答案(1)|浏览(174)

我目前使用的是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脚本中使用KEYSSCAN,它们的时间复杂度不是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);
        });
    }

是否有正确/推荐的方法?

7uzetpgm

7uzetpgm1#

在一个LUA脚本中使用KEYS和SCAN,它们的时间复杂度都是O(N)吗?
是的,它们都有O(N)的复杂度。所以你不应该在生产环境中使用它们。
那么,使用上面的脚本与使用...
如果有太多的键,那么带有解压缩keys结果的脚本可能会失败。因为,如果我没记错的话,Redis对命令的字节长度有限制。
既然SCAN使用了游标,那么同一个键怎么可能被多次返回呢?
因为通常情况下,密钥空间在扫描期间是动态的,例如添加新密钥、旧密钥过期或删除。

相关问题