Pit encountered when php uses redis scan command

In previous projects, the redis keys command was used to obtain certain keys. This command will block for a long time when the database is particularly large, so there is a big security risk, 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 that uses 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;
    }
}


Using the keys command, you can get the 5 keys of "test1", "test2",....., "test5", but nothing is output when using scan.

……

…………

………………

After multi-party analysis, it is finally found that there is a problem with the return value of the scan command.

In fact, the official document of redis also clearly stated that the scan command may return empty for each iteration, but this is not a sign of the end, but when the returned iteration value is "0", it will be considered as 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 a lot of 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 is almost inevitable.

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 way to solve this problem. There are two fundamental ways:

1.setOption

Set the behavior during iteration through the setOption function. The following is the sample code:
 

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


Compared with the above code, there is only one more setOption operation. What is the function of this operation? This operation is to tell the redis extension, when the scan command is executed, if the returned result set is empty, the function does not return, but directly continues to execute the scan command. Of course, these steps are automatically completed by the extension, when the scan function returns , Either return false, that is, the iteration ends, and no key matching the pattern pattern is found, or the matching key is returned, instead of returning an empty array.

2.while(true)

The above method is automatically completed by the PHP extension, then we can also change the writing method to achieve the same effect.
 

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


 

Guess you like

Origin blog.csdn.net/JineD/article/details/111285525