php使用redis的scan命令时遇到的坑

以前的项目中有用到redis的keys命令来获取某些key,这个命令在数据库特别大的情况会block很长一段时间,所以有很大的安全隐患,所以这次打算优化一下。

官网建议使用scan命令来代替。于是就用了……



以下是使用scan命令来匹配相应模式的key的代码:(结果啥也输出不了
 

$redis = new Redis();
$redis->connect('localhost', 6379);

$iterator = null;
while ($keys = $redis->scan($iterator, 'test*')) 
{ 
    foreach ($keys as $key) { 
        echo $key . PHP_EOL;
    }
}


使用keys命令可以得到设置的”test1″,”test2″,…..,”test5″这5个key,但是使用scan却什么也没有输出。

……

…………

………………

经过多方分析,最终发现,是scan命令的返回值有问题。

其实redis的官方文档也明确说了,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;
    }
}


和上面的代码相比,只是多了个setOption的操作,这个操作的作用是啥呢?这个操作就是告诉redis扩展,当执行scan命令后,返回的结果集为空的话,函数不返回,而是直接继续执行scan命令,当然,这些步骤都是由扩展自动完成,当scan函数返回的时候,要么返回false,即迭代结束,未发现匹配模式pattern的key,要么就返回匹配的key,而不再会返回空数组了。

2.while(true)

上面那种方式是由php的扩展自动完成的,那么我们也可以换一种写法来达到相同的效果。
 

$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;
    }
}


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

戴国进

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值