写点什么

我想模糊删除 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 keysend
复制代码


截屏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--'endredis.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--'endredis.call('unlink',unpack(list));return t[1];
复制代码


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

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

还未添加个人简介

评论

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