redisファジークエリのスキャンメソッドをカプセル化する
public function redisScan($pattern, $count = 1000){
$redis = new \myredis\Datasource();
$myredis = $redis::getRedis('instance1');
$ret = [];
$iterator = 0;
while (true) {
$result = $myredis->rawCommand("scan", $iterator, 'match', $pattern, 'count', $count);
// print_r($result);
// echo '<br>';
if ($result === false) {
break;
}
$ret = array_merge($ret, $result[1]);
$iterator = $result[0];
if($result[0] == 0){
break;
}
}
return $ret;
}
public function redisScanTest(){
$res=$this->dcscan('tp3_home_watch_mobile_invite_list*');
print_r($res);
}
/**
* redis里把tp3_home_watch_mobile_invite_list*出队列
*/
public function redisPull(){
while (true) {
$key = $this->redis->rpop('tp3_invite_list_key_mult');//tp3_home_watch_mobile_invite_list_46085
if($key){
$this->redis2mysql($key);
}else{
echo "deal finish";
return true;
}
}
echo 'success';
}
/**
* redis里把tp3_home_watch_mobile_invite_list*键写入redis队列
*/
public function redisPush(){
$res=$this->redisScan('tp3_home_watch_mobile_invite_list*');
// $res=['tp3_home_watch_mobile_invite_list_71354'];
foreach ($res as $k=>$v){
$this->redis->lpush('tp3_invite_list_key_mult',$v);
}
echo 'success';
}
Redisには古典的な問題があります。大量のデータの場合、特定のルールを満たすキーを見つけるのと同様の情報を取得する方法は2つあります
。1つはキーコマンドです。これは、Redisのため、シンプルで失礼です。はシングルスレッドです。1つの機能は、keysコマンドがブロック方式で実行され、トラバーサル方式で実装されるキーの複雑さがO(n)であることです。Redisライブラリ内のキーが多いほど、検索の実装コストが高くなります。ブロッキング時間が長くなります。
2つ目はスキャンコマンドです。これは、非ブロッキング方式でキー値検索を実現します。ほとんどの場合、キーコマンドを置き換えることができ、よりオプションです。
次のように、100,000個のテストデータをkey ***:value ***形式で書き込みます(ps:piplineを使用する場合、1w 1ストローク、各ストロークは数秒で完了します)
# -*- coding: utf-8 -*-
# !/usr/bin/env python3
import redis
import sys
import datetimedef create_testdata():
r = redis.StrictRedis(host='***.***.***.***', port=***, db=0, password='***')
counter = 0
with r.pipeline(transaction=False) as p:
for i in range(0, 100000):
p.set('key' + str(i), "value" + str(i))
counter = counter + 1
if (counter == 10000):
p.execute()
counter = 0
print("set by pipline loop")
if __name__ == "__main__":
create_testdata()
たとえば、ここのクエリでkey111で始まるキーは何ですか?
keysコマンドを使用する場合は、keys key1111 *を実行して一度にすべてを調べます。
同様に、scanコマンドを使用する場合
、scan 0 match key1111 * count 20scanの構文は次のとおりです。SCANカーソル[MATCHパターン] [ COUNTcount ]デフォルトのCOUNT値は10です。
SCANコマンドは、カーソルベースのイテレータです。これは、コマンドが呼び出されるたびに、前の反復プロセスを続行するために、前の呼び出しによって返されたカーソルを呼び出しのカーソルパラメーターとして使用する必要があることを意味します。
ここでは、scan 0 match key1111 * count 20コマンドを使用してこのクエリを完了します。少し予期しないのは、使用開始時にクエリ結果がないことです。これは、scanコマンドの原理によって異なります。
スキャンがキーをトラバースするとき、0は初めてを表し、key1111 *はkey1111の先頭でのパターンマッチングを表し、カウント20の20は修飾されたキーの出力を表しませんが、サーバーがトラバースできる辞書スロットの数を制限します一度に(ほぼ等しい)。
では、スロットデータとは何ですか?このスロットはRedisクラスターにありますか?答えは否定的です。実際、上の写真はすでに答えを与えています。
上記の「辞書スロット」の数がクラスター内のスロットの数であり、クラスター内のスロットの数が16,384であることがわかっている場合、16384スロットをトラバースした後、すべての重要な情報をトラバースする必要があります
。上記を明確に参照してください。トラバースする場合ディクショナリスロットの数が20,000の場合、カーソルはまだトラバース結果を終了していないため、このディクショナリスロットはクラスタ内のスロットの概念と同じではありません。
テスト後、スキャンするときに、条件を満たすキーに完全に一致するようにCOUNT値をトラバースできる量は、特定のオブジェクトのキーの数に関連します。キーの
数を超えるカウントでスキャンすると、次のようになります。たとえば、キーの数が10Wの場合、一度に20Wの辞書スロットをトラバースすると、確実に結果を完全にトラバースできます。
スキャン命令は一連の命令であり、すべてのキーをトラバースするだけでなく、指定されたコンテナセットをトラバースすることもできます。
zscanはzsetコレクション
の要素をトラバースし、hscanはハッシュディクショナリ
の要素をトラバースし、sscanはsetコレクションの要素をトラバースします。
SSCANコマンド、HSCANコマンド、およびZSCANコマンドの最初のパラメーターは、常にデータベースキー(指定されたキー)です。
さらに、redisデスクトップマネージャーを使用している場合、ライブラリが更新されると、コンソールがスキャンコマンドを自動的に更新するため、ライブラリが何をしているのかがわかります。