Redis(PHP-Redis)中SCAN与KEYS同模式返回结果不一致问题
我来帮你捋一捋这个问题,刚好我在项目里也遇到过类似的情况,咱们一步步拆解:
首先,你提到KEYS命令能正常返回结果,但SCAN却返回FALSE,这大概率不是Redis服务器本身的问题(毕竟3.1.6版本完全支持SCAN),而是PHP-Redis客户端的调用细节或者模式匹配的坑在作祟。
可能的原因及解决办法
1. 迭代器参数未正确传递引用
PHP-Redis的scan方法第一个参数要求是引用传递的迭代器变量,虽然在PHP 5.3+之后调用时不需要手动加&,但如果你的PHP版本偏旧,或者客户端版本有bug,就可能因为参数传递错误导致命令执行失败返回FALSE。
你可以尝试显式传递引用(针对旧PHP版本):
$iterator = 0; $result = $redis->scan(&$iterator, 'source_1234_[a-zA-Z]*_[0-9]*');
如果是新版本PHP,确保你初始化了$iterator为0,并且变量是可写的(不是常量或未定义的变量)。
2. SCAN的MATCH模式存在客户端解析差异
虽然Redis官方文档说明KEYS和SCAN的MATCH模式都是glob风格,但部分旧版本的PHP-Redis客户端对[]这种字符范围匹配的解析有问题,可能把[当成普通字符处理,导致匹配不到任何键,进而在某些场景下返回FALSE。
你可以先简化模式进行测试,比如用source_1234_test_*调用SCAN,如果能返回结果,就说明是[a-zA-Z]字符范围的解析问题。这种情况下,你可以换一种匹配方式,或者升级PHP-Redis客户端到最新稳定版(建议>=4.0.0)。
3. 错误的单次调用SCAN逻辑
SCAN是分批返回结果的,它需要循环调用直到迭代器变为0才能获取所有匹配的键。如果只调用一次,不仅可能拿不到全部结果,在某些极端情况下(比如第一次扫描就没有匹配到任何键,且迭代器直接变为0),客户端可能返回FALSE或者空数组。
正确的SCAN遍历写法应该是这样的:
$iterator = 0; $allResults = []; do { // 执行SCAN,迭代器会被自动更新 $response = $redis->scan($iterator, 'source_1234_[a-zA-Z]*_[0-9]*'); // 检查是否执行成功 if ($response === false) { break; // 命令执行出错,终止循环 } // 合并本次扫描到的结果 if (!empty($response[1])) { $allResults = array_merge($allResults, $response[1]); } } while ($iterator !== 0); // 迭代器为0时表示扫描完成 print_r($allResults);
这种写法能确保你拿到所有匹配的键,同时也能处理命令执行出错的情况。
4. PHP-Redis客户端版本过低
旧版本的PHP-Redis(比如2.2.0之前)对SCAN命令的实现存在一些bug,比如处理复杂模式时出错、返回值处理异常等。建议你升级到最新的稳定版,比如通过PECL重新安装:
pecl install redis
总结
先从检查迭代器的引用传递和正确的循环调用方式入手,再测试简化后的匹配模式,最后考虑升级客户端版本。按照这个步骤排查,应该能解决你遇到的问题。
内容的提问来源于stack exchange,提问作者Michael Millar

