如何使用纯Redis以原子方式删除与模式匹配的数百万个键?

Leo*_*llo 4 lua redis

假设我有数百万个prefix:<numeric_id>密钥。

我想以原子方式清除它们。

如何使用 Redis 以原子方式删除与模式匹配的键显示了许多选项。有些使用redis-cli或 Bash 脚本,但我需要以编程方式使用我的客户端来完成。

Lua 脚本方法很有前途,但使用KEYS命令的解决方案失败并出现“太多元素无法解包”错误。

如何实现这一目标?

Leo*_*llo 6

以下 Lua 脚本使用SCAN命令,因此它会在脚本中分块删除 - 避免“解压元素过多”错误。

local cursor = 0
local calls = 0
local dels = 0
repeat
    local result = redis.call('SCAN', cursor, 'MATCH', ARGV[1])
    calls = calls + 1
    for _,key in ipairs(result[2]) do
        redis.call('DEL', key)
        dels = dels + 1
    end
    cursor = tonumber(result[1])
until cursor == 0
return "Calls " .. calls .. " Dels " .. dels
Run Code Online (Sandbox Code Playgroud)

它返回SCAN调用了多少次以及删除了多少个键。

用于:

EVAL "local cursor = 0 local calls = 0 local dels = 0 repeat    local result = redis.call('SCAN', cursor, 'MATCH', ARGV[1])     calls = calls + 1   for _,key in ipairs(result[2]) do       redis.call('DEL', key)      dels = dels + 1     end     cursor = tonumber(result[1]) until cursor == 0 return 'Calls ' .. calls .. ' Dels ' .. dels" 0 prefix:1
Run Code Online (Sandbox Code Playgroud)

请注意,它会在运行时阻塞服务器,因此不建议按原样用于生产。

对于生产,请考虑更改DELUNLINK. 您还可以返回光标(而不是在脚本内重复直到它为零)并将 COUNT 参数添加到 SCAN 以进行节流(请参阅REDIS 中的 SCAN / HSCAN 命令是否有任何推荐的 COUNT 值?)。通过这种方式,您可以分块而不是一次性完成,类似于如何在 redis 中获取所有集合?

或者您可以使用以下答案中所述的方法做一些更复杂的事情:Redis `SCAN`:如何在可能匹配的新密钥之间保持平衡并确保在合理的时间内最终结果?