如何并行获取Redis指定前缀键值对?含哈希分区方案咨询
并行获取指定前缀Redis键值对的实现方案
非脚本实现方式(客户端侧过滤)
这种方式无需依赖Redis脚本,完全在客户端通过多线程/进程配合SCAN命令实现:
每个进程独立执行SCAN扫描
每个进程使用SCAN命令遍历匹配前缀的键,初始游标为0,命令格式:SCAN 0 MATCH "{你的前缀}*" COUNT 1000COUNT是Redis的提示参数,用于控制每次扫描返回的键数量(非精确值,可根据数据量调整为1000或更大)- 每次扫描会返回下一个游标和当前批次的键列表,直到游标返回0表示扫描完成
客户端侧过滤键
对每个批次返回的键,在客户端计算哈希值并过滤:- 要保证哈希计算逻辑统一,推荐使用Redis集群槽位的CRC16算法(
CRC16(key) & 0x3FFF),也可自定义哈希算法,只要所有进程保持一致即可 - 保留满足
(hash(key) % partition_size) == partition_id的键
- 要保证哈希计算逻辑统一,推荐使用Redis集群槽位的CRC16算法(
批量获取键值对
对过滤后的键,使用批量命令获取值:- 字符串类型用
MGET {key1} {key2} ... - 哈希类型用
HMGET或HGETALL(可批量封装) - 注意控制单次批量命令的键数量,避免请求过大阻塞Redis
- 字符串类型用
Lua脚本实现方式(Redis侧过滤)
通过Lua脚本在Redis端完成扫描+过滤+取值,减少客户端与Redis的网络传输量:
示例脚本
local prefix = ARGV[1] local partition_size = tonumber(ARGV[2]) local partition_id = tonumber(ARGV[3]) local cursor = tonumber(ARGV[4]) or 0 -- 执行SCAN扫描 local scan_result = redis.call('SCAN', cursor, 'MATCH', prefix .. '*', 'COUNT', 1000) local next_cursor = scan_result[1] local keys = scan_result[2] local filtered_kv = {} for _, key in ipairs(keys) do -- 用Redis内置CRC16计算键的哈希值(与集群槽位计算逻辑一致) local key_hash = redis.call('CRC16', key) if key_hash % partition_size == partition_id then -- 根据键类型获取值,这里以字符串类型为例,可按需修改 local value = redis.call('GET', key) table.insert(filtered_kv, {key, value}) end end -- 返回下一个游标和符合条件的键值对 return {next_cursor, filtered_kv}
执行脚本命令
EVAL "上述脚本内容" 0 "myprefix" 4 0 0
参数说明:
0:表示脚本没有键参数myprefix:目标键的前缀4:并行进程数(partition_size)0:当前进程的编号(partition_id)0:初始扫描游标
脚本执行逻辑
- 每次调用脚本返回下一个游标和当前批次的符合条件的键值对
- 客户端持续调用脚本,直到返回的游标为0,完成全量扫描
两种方式的对比
| 维度 | 非脚本方式 | Lua脚本方式 |
|---|---|---|
| 网络开销 | 较大(传输所有扫描到的键) | 较小(仅传输符合条件的键值对) |
| Redis阻塞风险 | 低(客户端拆分请求) | 高(大批次扫描可能阻塞单线程) |
| 实现复杂度 | 客户端需处理哈希计算和批量逻辑 | 脚本需适配不同键类型 |
| 一致性 | 依赖客户端哈希算法实现正确性 | 与Redis内部哈希逻辑完全一致 |
内容的提问来源于stack exchange,提问作者Igor Gatis
相关产品推荐
相关产品推荐

