ホームページ  >  記事  >  バックエンド開発  >  PHP が redis scan コマンドを使用するときに遭遇する落とし穴

PHP が redis scan コマンドを使用するときに遭遇する落とし穴

不言
不言オリジナル
2018-04-04 09:39:425038ブラウズ


以前のプロジェクトでは、特定のキーを取得するためにredisのkeysコマンドを使用していましたが、データベースが特に大きい場合、このコマンドは長時間ブロックされ、セキュリティ上のリスクが大きいため、今回はこのコマンドを使用する予定です。一度最適化してください。

公式ウェブサイトでは、代わりに scan コマンドを使用することを推奨しています。そこで私はそれを使用しました...


以下は、scan コマンドを使用して、対応するパターンのキーを照合するためのコードです:

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

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

このコードは問題ないはずですよね?これは、jetbrains 社が所有するソフトウェア phpstorm のコード プロンプト ライブラリから取得したもので、パターン パラメーターのみが追加されていますが、実行結果には問題があります。

PHP が redis scan コマンドを使用するときに遭遇する落とし穴

keysコマンドを使用すると、設定された5つのキー「test1」、「test2」、...、「test5」を取得できますが、scanを使用すると何も出力されません。

……

…………

………………

複数者による解析の結果、最終的にscanコマンドの戻り値に問題があることが判明しました。

実際、redisの公式ドキュメントにもscanコマンドは反復ごとにnullを返す可能性があると明記されていますが、これは終了の前兆ではなく、返された反復の値が「0」になった時点で終了します。

したがって、上記のコードを反復するときに、キーが返されない場合、$keys は空の配列になるため、while ループは自然に中断され、出力はありません。

この状況は、redis に多数のキーがある場合に特に顕著です。キーが数十または数百しかない場合、この状況はめったに発生しませんが、キーが数千万に達すると、この状況はほぼ確実に発生します。

この状況の発生を減らすために、スキャン関数の 3 番目のパラメーターの数をより大きな数に設定できます。しかし、これはこの問題の根本的な解決策ではありません。根本的な解決策は 2 つあります:

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

               

以上がPHP が redis scan コマンドを使用するときに遭遇する落とし穴の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。