背景
业务上有一批数据是按照每天的日期来进行存储的,同时也限制了队列的容量(防止大key问题),但是队列中或多或少有些数据未被消费(定时任务消费者处理不及时,跨天数据未被执行到),导致历史数据一直冗余占用内存,所以需要删除历史key,减少内存占用。
实现
首先通过特定的key类型找到需要删除的数据,业务上的key都带有日期,直接使用以下命令即可获取
keyredis执行:
keys *2023*
lua脚本
eval "return redis.call('keys', '*2023*')"
然后将keys分批,主要是防止keys结果太大,删除任务执行太慢。– 处理查询出来的所有key 分割成batchSize一批
-- 处理查询出来的所有key 分割成batchSize一批
local function splitList(inputList, batchSize)
local result = {}
local currentBatch = {}
for _, value in ipairs(inputList) do
table.insert(currentBatch, value)
if #currentBatch == batchSize then
table.insert(result, currentBatch)
currentBatch = {} -- 重置当前批次
end
end
-- 处理最后一批
if #currentBatch > 0 then
table.insert(result, currentBatch)
end
return result
end
最后遍历分批处理好的table,调用UNLINK异步删除。UNLINK和DEL都可以删除key,但是DEL是阻塞的,UNLINK是开启异步线程删除的,使用UNLINK删除key不会影响主线程接受其他命令,同时开启多个异步线程也可以更快删除大Key。
-- 记录总共删除的数量
local allDeleteNum = 0
-- 遍历keys(50一组批量删除)
for _, keys in ipairs(toDeleteBatchKeys) do
allDeleteNum = allDeleteNum + redis.call('UNLINK', unpack(keys))
end
完整代码
-- 处理查询出来的所有key 分割成batchSize一批
local function splitList(inputList, batchSize)
local result = {}
local currentBatch = {}
for _, value in ipairs(inputList) do
table.insert(currentBatch, value)
if #currentBatch == batchSize then
table.insert(result, currentBatch)
currentBatch = {} -- 重置当前批次
end
end
-- 处理最后一批
if #currentBatch > 0 then
table.insert(result, currentBatch)
end
return result
end
local toDeleteKeys = redis.call('keys', KEYS[1])
local batchSize = 50
local toDeleteBatchKeys = splitList(toDeleteKeys, batchSize);
local allDeleteNum = 0
for _, keys in ipairs(toDeleteBatchKeys) do
allDeleteNum = allDeleteNum + redis.call('UNLINK', unpack(keys))
end
return "DeleteNums " .. tostring(allDeleteNum)
这里同时提供一个java实现://java实现 Redisson
RScript script = redisson.getScript();
String lua = "local function splitList(inputList, batchSize)\n" +
" local result = {}\n" +
" local currentBatch = {}\n" +
"\n" +
" for _, value in ipairs(inputList) do\n" +
" table.insert(currentBatch, value)\n" +
"\n" +
" if #currentBatch == batchSize then\n" +
" table.insert(result, currentBatch)\n" +
" currentBatch = {} \n" +
" end\n" +
" end\n" +
"\n" +
" if #currentBatch > 0 then\n" +
" table.insert(result, currentBatch)\n" +
" end\n" +
"\n" +
" return result\n" +
"end\n" +
"\n" +
"\n" +
"local toDeleteKeys = redis.call('keys', KEYS[1])\n" +
"local batchSize = 50\n" +
"local toDeleteBatchKeys = splitList(toDeleteKeys, batchSize);\n" +
"\n" +
"local allDeleteNum = 0\n" +
"for _, keys in ipairs(toDeleteBatchKeys) do\n" +
" allDeleteNum = allDeleteNum + redis.call(\"UNLINK\", unpack(keys))\n" +
"end\n" +
"return \"DeleteNums \" .. tostring(allDeleteNum)";
Object deleteNums = script.eval(RScript.Mode.READ_ONLY, lua, RScript.ReturnType.VALUE, Collections.singletonList("key"));
log.info("{}", deleteNums);