Home  >  Article  >  Backend Development  >  Pitfalls encountered when PHP uses the redis scan command

Pitfalls encountered when PHP uses the redis scan command

不言
不言Original
2018-04-04 09:39:425038browse


In previous projects, the keys command of redis was used to obtain certain keys. This command will block for a long time when the database is particularly large, so There are huge security risks, so I plan to optimize it this time.

The official website recommends using the scan command instead. So I used it...


The following is the code to use the scan command to match the key of the corresponding pattern:

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

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

This code should be fine, right? This is taken from the code prompt library of phpstorm, a software owned by jetbrains company. Only the pattern parameter is added, but the running result is problematic.

Pitfalls encountered when PHP uses the redis scan command

Using the keys command can get the five keys "test1", "test2",...,"test5" set, but nothing is output when using scan. .

……

…………

………………

After many analyzes, it was finally discovered that the return value of the scan command is question.

In fact, the official document of redis also clearly states that the scan command may return null for each iteration, but this is not a sign of the end, but when the value of the returned iteration is "0" That's the end.

Therefore, when the above code is iterating, if no key is returned, $keys is an empty array, so the while loop is naturally interrupted, so there is no output.

This situation is especially obvious when there are many keys in redis. When there are only dozens or hundreds of keys, this situation rarely occurs, but when the keys reach tens of millions, this situation This will almost certainly happen.

To reduce the occurrence of this situation, you can set the third parameter count of the scan function to a larger number. But this is not the fundamental solution to this problem. There are two fundamental solutions:

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

               

The above is the detailed content of Pitfalls encountered when PHP uses the redis scan command. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn