众所周知,redis 可用用 keys 来模糊匹配,但是由于 redis 是单线程的,如果 keys 匹配数量过多,会造成阻塞,具体教训见 https://blog.fundebug.com/2018/09/21/redis_incident/
在 redis 官方手册中查找到可以用 scan 来代替 keys,代码:
$redis = new Redis();
$redis->connect('localhost', 6379);
$iterator = null;
while ($keys = $redis->scan($iterator, 'test*')) {
foreach ($keys as $key) {
echo $key . PHP_EOL;
}
}
但是并没有取到我想要的结果,原来 scan 命令每次迭代的时候,有可能返回空,但这并不是结束的标志,而是当返回的迭代的值为”0″时才算结束。
因此,上面的代码在迭代的时候,若没有 key 返回,$keys 是个空数组,所以 while 循环自然就中断了,所以没有任何输出。
这种情况在 redis 中 key 特别多的时候尤其明显,当 key 只有几十个上百个的时候,很少会出现这种情况,但是当 key 达到上千万,这种情况几乎必现。
要减少这种情况的出现,可以通过将 scan 函数的第三个参数 count 设定为一个较大的数。但这不是解决此问题的根本办法,根本办法有以下两种:
1.setOption
通过 setOption 函数来设定迭代时的行为。以下是示例代码:
$redis = new Redis();
$redis->connect('localhost', 6379);
$redis->setOption(Redis::OPT_SCAN,Redis::SCAN_RETRY);
$iterator = null;
while ($keys = $redis->scan($iterator, 'test*')) {
foreach ($keys as $key) {
echo $key . PHP_EOL;
}
}
2.也可以这种:
$redis = new Redis();
$redis->connect('localhost', 6379);
$iterator = null;
while (true) {
$keys = $redis->scan($iterator, 'test*');
if ($keys === false) {//迭代结束,未找到匹配pattern的key
return;
}
foreach ($keys as $key) {
echo $key . PHP_EOL;
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于