php使用redis的scan指令時所遇到的坑

不言
發布: 2023-03-23 07:50:01
原創
5030 人瀏覽過


以前的專案中有用到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;
    }
}
登入後複製

這程式碼應該沒問題吧?這是從jetbrains 公司旗下軟體phpstorm的程式碼提示庫中摘出來的,只加了pattern參數,但是運行結果卻是有問題的。

php使用redis的scan指令時所遇到的坑

使用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;
    }
}
登入後複製

               

以上是php使用redis的scan指令時所遇到的坑的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!