吾志所向,一往无前;愈挫愈奋,再接再厉

Redis中根据关键词模糊匹配key并批量删除

Posted on By Eironn

线上Redis存在大量不常用的冗余的值,对服务器的内存造成浪费,所以优化存入和过期逻辑,并手动清理无用的值。

一.登录Redis控制台

我们可以直接登录到redis控制台,使用原声的命令来执行删除(如DELKEYS等),但是不支持复杂的用法,也就是无法模糊的查询key进行批量删除。

参考:Redis官方命令地址

二.Redis客户端工具

Redis支持多种客户端工具,除了开发语言外,比较常用的是一款名为RedisCli的工具,实现根据key模糊删除的语句如下:

redis-cli -h 127.0.0.1 -p 6379 -a yourpassword keys "keyword*" |xargs redis-cli -h 127.0.0.1 -p 6379 -a youpassword del

-h指定host地址,默认127.0.0.1

-p指定port,默认6379

-a指定redis密码

keyword为指定的key的模糊关键词,*代表通配符。

这个命令使用的redis的命令是del,这种删除方式如果删除大批量的值会存在阻塞问题,因此生产环境是不推荐使用的;并且我执行上面命令没有成功,提示del缺少参数。因此上述命令只是作为记录和参考。

三.使用Redis的EVAL执行Lua脚本方式

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

redis2.8.0之后使用SCAN替代KEYS,对大批量的查询进行了优化,不会阻塞主进程

并且新版本(4.0.0之后)的redis使用UNLINK代替DEL命令。UNLINK会在另一个线程中执行内存的回收,不会阻塞正常的get set请求。

也就是本文采用的查询和删除方式。

lua的文件如下:

-- 选择要操作的数据库
redis.call("select",7)
--游标的id
local cursor = 0
--查找删除的key的数量
local keyNum = 0
repeat
  --使用scan搜索,cursor=0的时候标识一个新的迭代期,服务器返回0的时候表示迭代已经结束
  local res = redis.call("scan",cursor,"MATCH",KEYS[1])
  if(res ~= nil and #res>=0) then
    cursor = tonumber(res[1])
    local ks = res[2]
    if(ks ~= nil and #ks>0) then
      redis.replicate_commands()
      --循环删除当前迭代器迭代出的数据
      for i=1,#ks,1 do
        local key = tostring(ks[i])
        --使用UNLINK删除,区别于del的是这个是异步执行的
        --这条指令要版本大于4.0.0 小于4.0.0就使用del
        redis.call("UNLINK",key)
      end
      --统计删除的key的数量
      keyNum = keyNum + #ks
    end
  end
--当服务器返回0的时候,跳出循环
until( cursor <= 0 )

return keyNum

通过redis-cli执行脚本

# 通过redis-cli执行脚本
redis-cli -h 地址 -p 端口 -a 密码 --eval 以上创建文件的路径/clear_data.lua "需要删除的key的前缀_*"
# 多值传送示例
redis-cli -h 地址 -p 端口 -a 密码 --eval 以上创建文件的路径/clear_data.lua "key1" "key2" , "va1" "va2"
# 脚本调用示例
redis-cli -h 127.0.0.1 -p 6379 -a 123456789 --eval /usr/local/redis/clear_data.lua "test_*"

参考文章:

Redis EVAL执行Lua脚本之批量删除数据

我想模糊删除 redis key🤔