我想模糊删除 redis key🤔

发布于: 2020 年 07 月 16 日
我想模糊删除redis key🤔

前提

redis中存在很多key,可能随着业务的下架永远也用不到了,需要批量删除(当然也可以不处理,等redis内存不足的时候,自动去执行淘汰策略)。假设存在若干个如下模式的key,都是以 unkey 为前缀,现在希望批量删除。

截屏2020-07-16 下午2.43.17.png

redis 2.6.0 之前

通过 ​del 直接删除(不推荐)

redis官方中的 ​del 是不支持正则表达式的,但是你可以从网上找到相关的办法让 ​del 命令支持正则,因为不推荐,所有不展示

通过 ​shell 实现

redis中的 ​KEYS  是支持通过正则表达式获取匹配的key,然后通过管道传递给 ​xargs 进行删除

redis-cli KEYS "unkey*" | xargs redis-cli DEL

image.png

redis 2.6.0 之后

通过Lua脚本删除

redis 2.6.0 之后的版本支持通过 ​EVAL 或 ​EVALSHA 执行使用Lua。 可以保证操作的原子性,还可以通过 ​ ​script load  对脚本进行缓存,减少网络开销。使用lua 有更高的自由度,可以添加很多功能模块。

return redis.call('del',unpack(redis.call('keys','unkey*')))

基本流程是这样的,如果逻辑严谨的话,可以动态传入匹配的表达式,返回删除的key之类的逻辑。

-- 参数1: “un*” 正则表达式
local keys=redis.call('keys',ARGV[1]);
if #keys==0 then
return '--No match--'
else
redis.call('del',unpack(keys))
return keys
end

截屏2020-07-16 下午2.38.59.png

redis 2.8.0 之后

通过 ​SCAN 替代 ​KEYS 

redis的执行是单线程的(至少当前版本是),如果我们通过 ​KEYS 去批量的获取key,如果数量很大的话,会有问题:

  1. 没有limit,只能一次获取所有,如果数据量很大的话全部输出的话,交互不友好。

  2. keys 是遍历算法,时间复杂度是 O(n),如果数据量特别大的话,可能会导致服务卡顿,影响到正常业务。

如果我们用 ​SACN 替代的话,就会好很多:

  1. 时间复杂度虽然也是 O(n),但是它是通过游标分步进行的,不会阻塞线程

  2. 提供limit参数,控制返回的条数

-- 参数1: “un*” 正则表达式
-- 每次获取1000条(不一定返回1000条),进行删除
local cursor="0";
repeat
local t = redis.call('scan',cursor,'match',ARGV[1],'count',1000);
local list=t[2];
if #list==0 then
return '--over--'
end
redis.call('del',unpack(list));
cursor=t[1];
until cursor=="0"
return "over";

但是这样写是有问题的,这还是一次获取所有key,虽然每次都获取1000条,但是lua代码原子执行,还是会有一次获取很多阻塞线程的问题。

所有建议控制 每次获取的数量,然后多次执行,每次返回的游标给下次执行使用。

-- 参数1: “0” 游标
-- 参数2: “un*” 正则表达式
local t = redis.call('scan',ARGV[1],'match',ARGV[2],'count',1000);
local list=t[2];
if #list==0 then
return '--over--'
end
redis.call('del',unpack(list));
return t[1];

redis 4.0.0 之后

通过 ​UNLINK 替代 ​DEL 

正常的 ​del 是在主线程内执行,等待当前的 ​del 执行完成,下一个命令才会执行。而redis在4.0之后提供了更好的选择。

unlink 会在另一个线程中执行内存的回收,不会阻塞正常的get set请求,而且使用的方式也很简单,跟执行 ​del 一样。

所以说redis 4.0 之后就不再是单线程了,但是基本的操作还是在主线程内执行。

-- 参数1: “0” 游标
-- 参数2: “un*” 正则表达式
local t = redis.call('scan',ARGV[1],'match',ARGV[2],'count',1000);
local list=t[2];
if #list==0 then
return '--over--'
end
redis.call('unlink',unpack(list));
return t[1];

发布于: 2020 年 07 月 16 日 阅读数: 8
用户头像

山中兰花草

关注

人需要的归属感 永远在他的归属地 2018.06.30 加入

还未添加个人简介

评论

发布
暂无评论
我想模糊删除redis key🤔