如何通过Laravel Redis门面复现KEYS yourKey*命令效果
问题描述
在Redis CLI中执行KEYS yourKey*命令,可返回Redis集群中所有匹配前缀的键值对。
尝试通过多种方法获取Redis集群内的所有键及对应值,但均无法正常生效:检索了网络上的各类解决方案并逐一测试,同时查阅了Laravel官方文档,但文档未说明该操作的实现方式,也未明确该操作是否被支持。
核心诉求:如果该需求可实现,如何基于Laravel的Redis门面完成该操作?
已尝试的错误写法及返回结果:
// 尽管Redis集群中确实存在shopping_cart前缀的键且对应值存在,该方法仍返回null Redis::get('KEYS shopping_cart*'); // 尝试该方法依旧返回null Redis::get('shopping_cart*'); // 调用该方法返回错误:Cannot use 'KEYS' with redis-cluster. Redis::keys('shopping_cart*'); // 调用该方法返回错误:Cannot use 'SCAN' with redis-cluster. Redis::scan('shopping_cart*');
错误原因
Redis::get()的作用是获取单个完整key名对应的值,传入KEYS shopping_cart*、shopping_cart*时,客户端会把这两个字符串直接当做完整key去查询,Redis中不存在对应key,因此返回null。- 直接调用
Redis::keys()、Redis::scan()报错,是因为Laravel的Redis客户端默认对集群模式拦截了这两个命令:Redis集群的key分散在不同节点的哈希槽上,原生KEYS/SCAN默认仅在当前连接的单节点执行,客户端为了避免开发者误将单节点结果当做全集群结果,直接抛出错误拦截调用。
实现方案
Redis集群模式下无法通过单条命令拿到全集群匹配的key,需要遍历所有主节点分别执行查询,再汇总结果。
方案1:生产环境推荐(SCAN渐进式遍历,无阻塞风险)
SCAN是游标迭代式遍历,不会长时间阻塞Redis服务,适合生产环境使用,代码示例:
$prefix = 'shopping_cart*'; $matchedKeys = []; // 获取集群所有主节点实例 $cluster = Redis::connection()->client(); foreach ($cluster->masters() as $masterNode) { $iterator = null; // 逐批扫描当前节点的key,每批扫描100个,可根据实际调整 while (($keys = $masterNode->scan($iterator, $prefix, 100)) !== false) { if (!empty($keys)) { $matchedKeys = array_merge($matchedKeys, $keys); } } } // 批量获取匹配key对应的值 $keyValueMap = []; if (!empty($matchedKeys)) { $values = Redis::mget($matchedKeys); $keyValueMap = array_combine($matchedKeys, $values); }
如果MGET报跨槽错误,可将key按哈希槽分组后,对每个节点单独执行MGET即可。
方案2:仅适合本地测试/极低数据量场景(KEYS命令)
KEYS会全量遍历节点所有key,数据量稍大就会阻塞Redis服务,线上生产环境禁止使用,代码示例:
$prefix = 'shopping_cart*'; $matchedKeys = []; $cluster = Redis::connection()->client(); foreach ($cluster->masters() as $masterNode) { $nodeKeys = $masterNode->keys($prefix); if (!empty($nodeKeys)) { $matchedKeys = array_merge($matchedKeys, $nodeKeys); } } // 后续取值逻辑同方案1
内容的提问来源于stack exchange,提问作者temp
相关产品推荐
相关产品推荐

