如何使用纯 Redis 原子地删除数百万个匹配模式的键?
Posted
技术标签:
【中文标题】如何使用纯 Redis 原子地删除数百万个匹配模式的键?【英文标题】:How to atomically delete millions of keys matching a pattern using pure Redis? 【发布时间】:2020-08-05 13:12:25 【问题描述】:假设我有数百万个prefix:<numeric_id>
键。
我想以原子方式清除它们。
How to atomically delete keys matching a pattern using Redis 显示了许多选项。有些人使用redis-cli
或 Bash 脚本,但我需要使用我的客户端以编程方式进行。
Lua 脚本方法很有希望,但使用 KEYS
命令的解决方案会失败,并出现“太多元素无法解包”错误。
如何做到这一点?
【问题讨论】:
【参考方案1】:以下 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
它返回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
请注意,它会在运行时阻塞服务器,因此不建议按原样用于生产。
对于生产,请考虑将DEL
更改为UNLINK
。您还可以返回光标(而不是在脚本内重复直到它为零)并将 COUNT 参数添加到 SCAN 以限制(请参阅Is there any recommended value of COUNT for SCAN / HSCAN command in REDIS?)。这样你就可以分块而不是一次性完成,类似于How can I get all of the sets in redis?
或者您可以使用此答案中所述的方法做一些更复杂的事情:Redis `SCAN`: how to maintain a balance between newcomming keys that might match and ensure eventual result in a reasonable time?
【讨论】:
我用了你的脚本为什么结果是:"Calls 281447 Dels 0"
没有匹配模式的键?尝试SCAN
与您的匹配模式,看看是否有任何键匹配
谢谢,已经解决,问题出在我的模式上。【参考方案2】:
Lua 是一个不错的选择,只要您不使用 Redis 集群或您要删除的所有键都在同一个分片上。
如果您需要从多分片中删除键,您仍然可以使用 Lua,但您必须“手动”向所有分片发送 Eval
命令。
另一种方法是使用RedisGears(Redis 模块),它允许您根据某些标准编写跨集群的 del 命令。
查看示例:https://oss.redislabs.com/redisgears/examples.html#delete-by-key-prefix
【讨论】:
以上是关于如何使用纯 Redis 原子地删除数百万个匹配模式的键?的主要内容,如果未能解决你的问题,请参考以下文章
在一个线程上删除具有数百万个字符串的大型哈希图会影响另一个线程的性能