如何编写LUA SCAN查找缺失Z字段的Redis HSET键(支持非阻塞)
非阻塞Redis Lua脚本:查找无Z字段的Hash键
直接上可运行的Lua脚本,基于Redis的SCAN命令实现非阻塞扫描,避免KEYS命令的阻塞问题:
-- 参数:1. 起始游标(首次调用传0);2. 匹配模式(可选,默认匹配所有键,比如'TEST:*');3. 每次扫描的数量(可选,默认100) local cursor = tonumber(ARGV[1]) or 0 local pattern = ARGV[2] or '*' local count = tonumber(ARGV[3]) or 100 local result = {} local scan_result = redis.call('SCAN', cursor, 'MATCH', pattern, 'COUNT', count) local next_cursor = tonumber(scan_result[1]) local keys = scan_result[2] for _, key in ipairs(keys) do -- 只处理Hash类型的键 if redis.call('TYPE', key)['ok'] == 'hash' then -- 检查是否不存在Z字段 if redis.call('HEXISTS', key, 'Z') == 0 then table.insert(result, key) end end end -- 返回下一个游标和找到的符合条件的键列表 return {next_cursor, result}
脚本说明
- 非阻塞特性:依赖
SCAN命令的迭代式扫描,不会一次性遍历所有键,避免阻塞Redis主线程,适合大键量的生产环境。 - 参数灵活:
- 第一个参数是扫描游标,首次调用传
0,后续每次用上一次返回的游标值,直到返回游标为0表示扫描完成。 - 第二个参数是键匹配模式,比如你可以传
TEST:*来只扫描以TEST:开头的键,缩小扫描范围。 - 第三个参数是每次扫描的键数量,默认100,可根据实际情况调整。
- 第一个参数是扫描游标,首次调用传
- 过滤逻辑:
- 先判断键的类型是否为Hash,避免误处理其他类型的键。
- 用
HEXISTS检查Hash中是否存在Z字段,返回0表示不存在,将该键加入结果列表。
使用示例
假设你的Redis实例中有题目中的两个Hash键:
HSET 'TEST:1' X 10 Y 20 Z 10 HSET 'TEST:2' X 10 Y 20
首次调用脚本:
EVAL "上面的Lua脚本内容" 0 0 'TEST:*'
返回结果类似:[0, ["TEST:2"]](游标返回0表示扫描完成,结果列表包含TEST:2)
如果键量很大,首次返回的游标可能不是0,比如返回[123, ["TEST:2", "TEST:5"]],那么下一次调用就传游标123:
EVAL "上面的Lua脚本内容" 0 123 'TEST:*'
重复此过程直到游标返回0,收集所有结果列表中的键即可。
注意事项
- 因为
SCAN可能会返回重复的键,脚本中没有去重逻辑,如果你的业务场景需要严格去重,可以在客户端收集结果时自行处理。 - 如果Redis版本低于2.8,不支持
SCAN命令,此时只能退而求其次用KEYS命令,但会阻塞主线程,不推荐在生产环境大键量下使用。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

