以前のプロジェクトでは、redisキーコマンドを使用して特定のキーを取得していましたが、データベースが特に大きい場合、このコマンドは長時間ブロックされるため、セキュリティリスクが大きいため、今回は最適化する予定です。
公式ウェブサイトでは、代わりにscanコマンドを使用することをお勧めします。だから私はそれを使用しました...
以下は、対応するパターンのキーを照合するためにスキャンコマンドを使用するコードです。
$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つのキーを取得できますが、スキャンを使用しても何も出力されません。
......
............
..................
マルチパーティの分析の後、最終的にスキャンコマンドの戻り値に問題があることが分かりました。
実際、redisの公式文書には、スキャンコマンドが反復ごとに空を返す可能性があることも明記されていますが、これは終了の兆候ではありませんが、返された反復値が「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操作は1つだけですが、この操作の機能は何ですか?この操作は、スキャンコマンドが実行されたときに、返された結果セットが空の場合、関数は戻りませんが、スキャンコマンドを直接実行し続けることをredis拡張機能に通知します。もちろん、これらの手順は拡張機能によって自動的に完了します。 、スキャン関数がを返す場合、falseを返す、つまり反復が終了し、パターンパターンに一致するキーが見つからないか、空の配列を返す代わりに一致するキーが返されます。
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;
}
}