私のRedis DBには、いくつかのprefix:<numeric_id>
ハッシュがあります。
時々私はそれらをすべてアトミックにパージしたいです。分散ロックメカニズムを使用せずにこれを行うにはどうすればよいですか?
私のRedis DBには、いくつかのprefix:<numeric_id>
ハッシュがあります。
時々私はそれらをすべてアトミックにパージしたいです。分散ロックメカニズムを使用せずにこれを行うにはどうすればよいですか?
回答:
redis 2.6.0以降では、アトミックに実行されるluaスクリプトを実行できます。書いたことはありませんが、こんな感じになると思います
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
警告:パフォーマンスの問題のため、Redisドキュメントに記載されているように、
keys
コマンドは本番環境での通常の操作には使用できません。このコマンドは、デバッグと特別な操作を目的としています。続きを読む
EVALのドキュメントを参照してください。
EVAL "local keys = redis.call('keys', ARGV[1]) \n for i=1,#keys,5000 do \n redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) \n end \n return keys" 0 prefix:*
del prefix:*
基本的な操作のようです:/
EVAL "return redis.call('del', 'defaultKey', unpack(redis.call('keys', ARGV[1])))" 0 prefix:*
bashで実行:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
更新
わかった。この方法について:現在の追加の増分プレフィックスを保存し、すべてのキーに追加します。例えば:
次のような値があります。
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
データをパージする必要がある場合は、最初にprefix_actuallを変更して(たとえば、set prefix_prefix_actuall = 3)、アプリケーションが新しいデータをキーprefix:3:1およびprefix:3:2に書き込むようにします。次に、prefix:2:1およびprefix:2:2から古い値を安全に取得し、古いキーを削除できます。
redis-cli KEYS "prefix:*" | xargs --delim='\n' redis-cli DEL
redis-cli -n 3 KEYS "prefix:*" | xargs redis-cli -n 3 DEL
これは、Luaに実装されたワイルドカード削除の完全に機能するアトミックバージョンです。ネットワークのやり取りがはるかに少ないため、xargsバージョンよりもはるかに高速に実行されます。また、完全にアトミックであり、終了するまでredisに対する他の要求をブロックします。Redis 2.6.0以降でキーをアトミックに削除したい場合、これは間違いなく実行する方法です。
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
これは、この質問に対する彼の回答における@mcdizzleのアイデアの作業バージョンです。アイデアのクレジットは100%です。
編集:以下のKikitoのコメントによると、Redisサーバーの空きメモリよりも削除するキーの数が多い場合、「アンパックするには要素が多すぎます」というエラーが発生します。その場合は、次のようにします。
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
キキトが示唆したように。
for _,k in ipairs(redis.call('keys', KEYS[1])) do redis.call('del', k) end
unpack
は「独立変数のリスト」(他の言語ではと呼ばれますexplode
)のテーブルを変換しますが、最大数はシステムメモリに依存しません。LUAI_MAXSTACK
定数を介してluaで固定されています。Lua 5.1およびLuaJITでは8000、Lua 5.2では100000です。forループオプションはIMOをお勧めします。
EVAL
操作対象のキーを事前に指定していないため、のセマンティクスに違反します。単一のインスタンスで動作するはずですが、Redisクラスターで動作するとは期待できません。
免責事項:次の解決策は原子性を提供しません。
v2.8以降では、KEYS [1]の代わりにSCANコマンドを本当に使用したいと考えています。次のBashスクリプトは、パターンによるキーの削除を示しています。
#!/bin/bash
if [ $# -ne 3 ]
then
echo "Delete keys from Redis matching a pattern using SCAN & DEL"
echo "Usage: $0 <host> <port> <pattern>"
exit 1
fi
cursor=-1
keys=""
while [ $cursor -ne 0 ]; do
if [ $cursor -eq -1 ]
then
cursor=0
fi
reply=`redis-cli -h $1 -p $2 SCAN $cursor MATCH $3`
cursor=`expr "$reply" : '\([0-9]*[0-9 ]\)'`
keys=${reply##[0-9]*[0-9 ]}
redis-cli -h $1 -p $2 DEL $keys
done
[1] KEYSは、DoSを引き起こす可能性のある危険なコマンドです。以下は、そのドキュメントページからの引用です。
警告: KEYSは、実稼働環境でのみ細心の注意を払って使用する必要があるコマンドと見なしてください。大規模なデータベースに対して実行すると、パフォーマンスが低下する可能性があります。このコマンドは、デバッグや、キースペースレイアウトの変更などの特別な操作を目的としています。通常のアプリケーションコードではKEYSを使用しないでください。キースペースのサブセットでキーを見つける方法を探している場合は、セットの使用を検討してください。
更新:同じ基本的な効果のための1つのライナー-
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
-n 1
それぞれにredis-cli
:呼び出しredis-cli -n 1 --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli -n 1 DEL
redis 3.2.8で以下のコマンドを使用しています
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
あなたはここからキーパターン検索に関連するより多くのヘルプを得ることができます:-https : //redis.io/commands/keys。以下のようなあなたの要件ごとに、あなたの便利なglobスタイルのパターンを使用する*YOUR_KEY_PREFIX*
か、YOUR_KEY_PREFIX??
または任意の他の。
そして、あなたのいずれかがRedis PHPライブラリを統合している場合は、以下の機能が役立ちます。
flushRedisMultipleHashKeyUsingPattern("*YOUR_KEY_PATTERN*"); //function call
function flushRedisMultipleHashKeyUsingPattern($pattern='')
{
if($pattern==''){
return true;
}
$redisObj = $this->redis;
$getHashes = $redisObj->keys($pattern);
if(!empty($getHashes)){
$response = call_user_func_array(array(&$redisObj, 'del'), $getHashes); //setting all keys as parameter of "del" function. Using this we can achieve $redisObj->del("key1","key2);
}
}
ありがとうございました :)
このコマンドを使用してキーを削除することもできます:-
あなたのredisには多くのタイプのキーがあると仮定します-
例 ' xyz_category_fpc 'ここでxyzはサイト名であり、これらのキーはeコマースサイトの製品とカテゴリに関連し、FPCによって生成されます。
このコマンドを次のように使用すると、
redis-cli --scan --pattern 'key*' | xargs redis-cli del
または
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
' xyz_category_fpc '(1、2、3キーを削除)のようなすべてのキーを削除します。他の4、5、6の数字キーを削除するには、上記のコマンドで「xyz_product_fpc」を使用します。
あなたがしたい場合はすべて削除してのRedis、これらCommands-に従ってください
redis-cliを使用:
例:-シェルで:
redis-cli flushall
redis-cli flushdb
redis-cli del
はアトミックではありません。
私は同じ問題を抱えていました。ユーザーのセッションデータを次の形式で保存しました。
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
したがって、各エントリは個別のキーと値のペアでした。セッションが破棄されたときに、パターンのキーを削除してすべてのセッションデータを削除したかっsession:sessionid:*
たのですが、redisにはそのような機能はありません。
私がしたこと:セッションデータをハッシュ内に保存します。私はちょうどのハッシュIDを持つハッシュを作成session:sessionid
し、その後、私がプッシュするkey-x
、key-y
、key-z
そのハッシュに(順序は私には問題ではありませんでした)と私は、ハッシュはもう私はちょうど行うことを必要いけない場合DEL session:sessionid
、そのハッシュIDに関連付けられているすべてのデータがなくなっています。DEL
アトミックであり、データへのアクセス/ハッシュへのデータの書き込みはO(1)です。
あなたに役立つかもしれないと思うのはMULTI / EXEC / DISCARDです。されていないが、トランザクションの100%と同等、あなたが他の更新プログラムから削除を分離することができるはずです。
ご参考までに。
redis-cli
keys
(これはを使用していますscan
)大文字だけを変更する必要があるかもしれません。
scan-match.sh
#!/bin/bash
rcli=“/YOUR_PATH/redis-cli"
default_server="YOUR_SERVER"
default_port="YOUR_PORT"
servers=`$rcli -h $default_server -p $default_port cluster nodes | grep master | awk '{print $2}' | sed 's/:.*//'`
if [ x"$1" == "x" ]; then
startswith="DEFAULT_PATTERN"
else
startswith="$1"
fi
MAX_BUFFER_SIZE=1000
for server in $servers; do
cursor=0
while
r=`$rcli -h $server -p $default_port scan $cursor match "$startswith*" count $MAX_BUFFER_SIZE `
cursor=`echo $r | cut -f 1 -d' '`
nf=`echo $r | awk '{print NF}'`
if [ $nf -gt 1 ]; then
for x in `echo $r | cut -f 1 -d' ' --complement`; do
echo $x
done
fi
(( cursor != 0 ))
do
:
done
done
clear-redis-key.sh
#!/bin/bash
STARTSWITH="$1"
RCLI=YOUR_PATH/redis-cli
HOST=YOUR_HOST
PORT=6379
RCMD="$RCLI -h $HOST -p $PORT -c "
./scan-match.sh $STARTSWITH | while read -r KEY ; do
$RCMD del $KEY
done
bashプロンプトで実行する
$ ./clear-redis-key.sh key_head_pattern
Guide$CLASSMETADATA][1]
たとえば、キーに特殊文字が含まれていると、他の回答が機能しない場合があります。各キーを引用符にラップすると、適切に削除されます。
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
KEYS(運用サーバーで推奨)ではなくSCANを使用し--pipe
、xargs を使用しないバージョン。
xargsよりもパイプを使用する方が効率的であり、キーに引用符や、シェルが試して解釈するその他の特殊文字が含まれている場合に機能するためです。この例の正規表現の置換では、キーを二重引用符で囲み、内部のすべての二重引用符をエスケープします。
export REDIS_HOST=your.hostname.com
redis-cli -h "$REDIS_HOST" --scan --pattern "YourPattern*" > /tmp/keys
time cat /tmp/keys | perl -pe 's/"/\\"/g;s/^/DEL "/;s/$/"/;' | redis-cli -h "$REDIS_HOST" --pipe
これは質問への直接の回答ではありませんが、自分の回答を探すときにここにたどり着いたので、ここで共有します。
一致する必要があるキーが数千万から数億個ある場合、ここでの回答により、Redisはかなりの時間(分)応答しなくなり、メモリ消費のためにクラッシュする可能性があります(バックグラウンドでの保存は確実に行われます)。操作の途中で開始します)。
次のアプローチは紛れもなく醜いですが、私はより良いものを見つけませんでした。原子性はここでは問題外です。この場合の主な目標は、Redisを常に稼働状態に保ち、100%応答できるようにすることです。いずれかのデータベースにすべてのキーがあり、どのパターンにも一致する必要がない場合は完全に機能しますが、ブロックする性質があるため、http://redis.io/commands/FLUSHDBを使用できません。
アイデアは簡単です:ループで実行され、http://redis.io/commands/SCANやhttp://redis.io/commands/RANDOMKEYなどのO(1)操作を使用してキーを取得するスクリプトを記述し、それらがパターンに一致させ(必要な場合)、1つずつhttp://redis.io/commands/DELします。
それを行うより良い方法がある場合は、私に知らせてください。答えを更新します。
Rubyでのrandomkeyを使用した実装の例、rakeタスク、非ブロッキング置換redis-cli -n 3 flushdb
:
desc 'Cleanup redis'
task cleanup_redis: :environment do
redis = Redis.new(...) # connection to target database number which needs to be wiped out
counter = 0
while key = redis.randomkey
puts "Deleting #{counter}: #{key}"
redis.del(key)
counter += 1
end
end
FastoRedisの「ブランチの削除」機能を使用して簡単に実装できます。削除するブランチを選択するだけです。
上記のほとんどの方法を試しましたが、うまくいきませんでした。いくつか検索したところ、次の点が見つかりました。
-n [number]
del
しかし、キーの数千または数百万人が存在する場合、それが使用することをお勧めしますunlink
ので、アンリンクは、非ブロッキングであるデルは、より多くの情報訪問のために、このページをブロックしている間、デル対リンク解除をkeys
、デルのようであり、ブロックしていますだから私はこのコードを使ってパターンでキーを削除しました:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
ツールの使用やLua式の実行に関連するすべての回答をサポートします。
私の側からのもう一つのオプション:
私たちの運用データベースと運用前データベースには、何千ものキーがあります。場合によっては、いくつかのキー(マスクによって)を削除したり、いくつかの基準によって変更したりする必要があります。もちろん、特にシャーディング(各物理で512の論理DB)を使用して、CLIから手動で行う方法はありません。
この目的のために、このすべての作業を行うJavaクライアントツールを作成します。キーを削除する場合、ユーティリティは非常に単純で、そこにあるクラスは1つだけです。
public class DataCleaner {
public static void main(String args[]) {
String keyPattern = args[0];
String host = args[1];
int port = Integer.valueOf(args[2]);
int dbIndex = Integer.valueOf(args[3]);
Jedis jedis = new Jedis(host, port);
int deletedKeysNumber = 0;
if(dbIndex >= 0){
deletedKeysNumber += deleteDataFromDB(jedis, keyPattern, dbIndex);
} else {
int dbSize = Integer.valueOf(jedis.configGet("databases").get(1));
for(int i = 0; i < dbSize; i++){
deletedKeysNumber += deleteDataFromDB(jedis, keyPattern, i);
}
}
if(deletedKeysNumber == 0) {
System.out.println("There is no keys with key pattern: " + keyPattern + " was found in database with host: " + host);
}
}
private static int deleteDataFromDB(Jedis jedis, String keyPattern, int dbIndex) {
jedis.select(dbIndex);
Set<String> keys = jedis.keys(keyPattern);
for(String key : keys){
jedis.del(key);
System.out.println("The key: " + key + " has been deleted from database index: " + dbIndex);
}
return keys.size();
}
}
以下のコマンドは私のために働きました。
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
Spring RedisTemplate自体が機能を提供します。最新バージョンのRedissonClientは、「deleteByPattern」機能を廃止しました。
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
keys
とdelete
メソッドの呼び出しの間に表示される新しいキーがあります。