In meiner Redis DB habe ich eine Reihe von prefix:<numeric_id>
Hashes.
Manchmal möchte ich sie alle atomar reinigen. Wie mache ich das, ohne einen verteilten Verriegelungsmechanismus zu verwenden?
In meiner Redis DB habe ich eine Reihe von prefix:<numeric_id>
Hashes.
Manchmal möchte ich sie alle atomar reinigen. Wie mache ich das, ohne einen verteilten Verriegelungsmechanismus zu verwenden?
Antworten:
Ab redis 2.6.0 können Sie lua-Skripte ausführen, die atomar ausgeführt werden. Ich habe noch nie einen geschrieben, aber ich denke, er würde ungefähr so aussehen
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Warnung : Wie im Redis-Dokument angegeben,
keys
sollte der Befehl aus Leistungsgründen nicht für reguläre Vorgänge in der Produktion verwendet werden. Dieser Befehl ist für das Debuggen und spezielle Vorgänge vorgesehen. Weiterlesen
Siehe die EVAL-Dokumentation .
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:*
eine grundlegende Operation zu sein: /
EVAL "return redis.call('del', 'defaultKey', unpack(redis.call('keys', ARGV[1])))" 0 prefix:*
In Bash ausführen:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
AKTUALISIEREN
OK ich habe verstanden. Was ist mit dieser Methode: Speichern Sie das aktuelle zusätzliche inkrementelle Präfix und fügen Sie es allen Ihren Schlüsseln hinzu. Zum Beispiel:
Sie haben Werte wie diese:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
Wenn Sie Daten löschen müssen, ändern Sie zuerst prefix_actuall (z. B. setzen Sie prefix_prefix_actuall = 3), damit Ihre Anwendung neue Daten in das Schlüsselpräfix 3: 1 und das Präfix 3: 2 schreibt. Dann können Sie sicher alte Werte aus Präfix: 2: 1 und Präfix: 2: 2 übernehmen und alte Schlüssel löschen.
redis-cli KEYS "prefix:*" | xargs --delim='\n' redis-cli DEL
redis-cli -n 3 KEYS "prefix:*" | xargs redis-cli -n 3 DEL
Hier ist eine vollständig funktionierende und atomare Version eines in Lua implementierten Wildcard-Löschvorgangs. Es läuft viel schneller als die xargs-Version, da das Netzwerk viel weniger hin und her geht, und es ist vollständig atomar und blockiert alle anderen Anforderungen gegen Redis, bis es fertig ist. Wenn Sie Schlüssel in Redis 2.6.0 oder höher atomar löschen möchten, ist dies definitiv der richtige Weg:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
Dies ist eine funktionierende Version von @ mcdizzles Idee in seiner Antwort auf diese Frage. Die Idee zu 100% geht an ihn.
BEARBEITEN: Laut Kikitos Kommentar unten tritt der Fehler "Zu viele Elemente zum Entpacken" auf , wenn Sie mehr Schlüssel zum Löschen als freien Speicher auf Ihrem Redis-Server haben . In diesem Fall tun Sie:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Wie Kikito vorgeschlagen hat.
for _,k in ipairs(redis.call('keys', KEYS[1])) do redis.call('del', k) end
unpack
transformiert eine Tabelle in eine "Liste unabhängiger Variablen" (andere Sprachen nennen das explode
), aber die maximale Anzahl hängt nicht vom Systemspeicher ab. Es ist in Lua durch die LUAI_MAXSTACK
Konstante festgelegt. In Lua 5.1 & LuaJIT sind es 8000 und in Lua 5.2 100000. Die Option for loop wird IMO empfohlen.
EVAL
da sie die Schlüssel, mit denen sie arbeiten wird, nicht im Voraus angibt. Es sollte auf einer einzelnen Instanz funktionieren, aber erwarten Sie nicht, dass es mit Redis Cluster funktioniert.
Haftungsausschluss: Die folgende Lösung bietet keine Atomizität.
Ab v2.8 bist du wirklich möchten den Befehl SCAN anstelle von KEYS [1] verwenden. Das folgende Bash-Skript demonstriert das Löschen von Schlüsseln nach Muster:
#!/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 ist ein gefährlicher Befehl, der möglicherweise zu einem DoS führen kann. Das Folgende ist ein Zitat aus der Dokumentationsseite:
Warnung: Betrachten Sie KEYS als Befehl, der nur in Produktionsumgebungen mit äußerster Sorgfalt verwendet werden sollte. Dies kann die Leistung beeinträchtigen, wenn es für große Datenbanken ausgeführt wird. Dieser Befehl dient zum Debuggen und für spezielle Vorgänge, z. B. zum Ändern des Keyspace-Layouts. Verwenden Sie KEYS nicht in Ihrem regulären Anwendungscode. Wenn Sie nach einer Möglichkeit suchen, Schlüssel in einer Teilmenge Ihres Schlüsselraums zu finden, sollten Sie Mengen verwenden.
UPDATE: Ein Einzeiler für den gleichen Grundeffekt -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
-n 1
jedem redis-cli
Aufruf Folgendes hinzufügen :redis-cli -n 1 --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli -n 1 DEL
Für diejenigen, die Probleme hatten, andere Antworten zu analysieren:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
Ersetzen Sie key:*:pattern
durch Ihr eigenes Muster und geben Sie dieses einredis-cli
und Sie können loslegen.
Kredit lisco von: http://redis.io/commands/del
Ich benutze den folgenden Befehl in redis 3.2.8
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
Weitere Hilfe zur Suche nach Schlüsselmustern erhalten Sie hier: - https://redis.io/commands/keys . Verwenden Sie Ihr praktisches Muster im Glob-Stil gemäß Ihren Anforderungen wie *YOUR_KEY_PREFIX*
oderYOUR_KEY_PREFIX??
oder andere.
Und wenn einer von Ihnen die Redis PHP-Bibliothek integriert hat, hilft Ihnen die folgende Funktion.
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);
}
}
Vielen Dank :)
Die Lösung von @ mcdizle funktioniert nicht, sondern nur für einen Eintrag.
Dieser funktioniert für alle Schlüssel mit demselben Präfix
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
Hinweis: Sie sollten 'Präfix' durch Ihr Schlüsselpräfix ersetzen ...
Mit diesem Befehl können Sie auch die Schlüssel löschen: -
Angenommen, Ihre Redis enthalten viele Arten von Schlüsseln.
Beispiel: ' xyz_category_fpc ' hier ist xyz ein Site-Name . Diese Schlüssel beziehen sich auf Produkte und Kategorien einer E-Commerce-Site und werden von FPC generiert.
Wenn Sie diesen Befehl wie folgt verwenden:
redis-cli --scan --pattern 'key*' | xargs redis-cli del
ODER
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Es löscht alle Schlüssel wie ' xyz_category_fpc ' (lösche 1, 2 und 3 Schlüssel). Verwenden Sie zum Löschen anderer 4, 5 und 6 Zifferntasten ' xyz_product_fpc ' im obigen Befehl.
Wenn Sie alles in Redis löschen möchten , befolgen Sie diese Befehle.
Mit redis-cli:
Zum Beispiel: - in Ihrer Shell:
redis-cli flushall
redis-cli flushdb
redis-cli del
ist nicht atomar.
@ itamars Antwort ist großartig, aber das Parsen der Antwort hat bei mir nicht funktioniert, insb. in dem Fall, in dem in einem bestimmten Scan keine Schlüssel gefunden wurden. Eine möglicherweise einfachere Lösung direkt von der Konsole aus:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
Dies verwendet auch SCAN, das KEYS in der Produktion vorzuziehen ist, aber nicht atomar ist.
Ich hatte gerade das gleiche Problem. Ich habe Sitzungsdaten für einen Benutzer im folgenden Format gespeichert:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
Jeder Eintrag war also ein separates Schlüssel-Wert-Paar. Wenn die Sitzung zerstört wird, wollte ich alle Sitzungsdaten entfernen, indem ich Schlüssel mit dem Muster session:sessionid:*
lösche - aber redis hat keine solche Funktion.
Was ich getan habe: Speichern Sie die Sitzungsdaten in einem Hash . Ich schaffe nur einen Hash mit der Hash - ID von session:sessionid
und dann schiebe ich key-x
, key-y
, key-z
dass Hash (um mich nicht Sache tat) , und wenn ich nicht brauchen , dass Hash mehr ich nur zu tun , DEL session:sessionid
und alle Daten mit der Hash - ID zugeordnet sind weg. DEL
ist atomar und der Zugriff auf Daten / das Schreiben von Daten in den Hash ist O (1).
Ich denke, was Ihnen helfen könnte, ist MULTI / EXEC / DISCARD . Obwohl dies nicht zu 100% den Transaktionen entspricht , sollten Sie in der Lage sein, die Löschvorgänge von anderen Aktualisierungen zu isolieren.
Zu Ihrer Information.
redis-cli
keys
(dies verwendet scan
)Möglicherweise müssen Sie nur Großbuchstaben ändern.
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
Führen Sie an der Bash-Eingabeaufforderung aus
$ ./clear-redis-key.sh key_head_pattern
Andere Antworten funktionieren möglicherweise nicht, wenn Ihr Schlüssel spezielle Zeichen enthält - Guide$CLASSMETADATA][1]
zum Beispiel. Wenn Sie jeden Schlüssel in Anführungszeichen setzen, wird sichergestellt, dass er ordnungsgemäß gelöscht wird:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
Eine Version, die SCAN anstelle von KEYS (wie für Produktionsserver empfohlen) und --pipe
nicht von xargs verwendet.
Ich bevorzuge Pipe gegenüber Xargs, weil es effizienter ist und funktioniert, wenn Ihre Schlüssel Anführungszeichen oder andere Sonderzeichen enthalten, mit denen Ihre Shell versucht, sie zu interpretieren. Die Regex-Ersetzung in diesem Beispiel umschließt den Schlüssel in doppelte Anführungszeichen und entgeht allen doppelten Anführungszeichen.
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
Dies ist keine direkte Antwort auf die Frage, aber da ich bei der Suche nach meinen eigenen Antworten hierher gekommen bin, werde ich dies hier teilen.
Wenn Sie Dutzende oder Hunderte von Millionen von Schlüsseln haben, die Sie abgleichen müssen, führen die hier gegebenen Antworten dazu, dass Redis längere Zeit (Minuten?) Nicht reagiert und möglicherweise aufgrund des Speicherverbrauchs abstürzt (stellen Sie sicher, dass das Speichern im Hintergrund funktioniert) treten Sie mitten in Ihrer Operation ein).
Der folgende Ansatz ist zweifellos hässlich, aber ich habe keinen besseren gefunden. Atomarität kommt hier nicht in Frage. In diesem Fall besteht das Hauptziel darin, Redis 100% der Zeit auf dem Laufenden zu halten und zu reagieren. Es funktioniert perfekt, wenn Sie alle Schlüssel in einer der Datenbanken haben und kein Muster abgleichen müssen, aber http://redis.io/commands/FLUSHDB nicht verwenden können, da es die Natur blockiert.
Die Idee ist einfach: Schreiben Sie ein Skript, das in einer Schleife ausgeführt wird und eine O (1) -Operation wie http://redis.io/commands/SCAN oder http://redis.io/commands/RANDOMKEY verwendet , um Schlüssel abzurufen , und prüfen Sie, ob diese vorhanden sind Passen Sie das Muster an (falls erforderlich) und http://redis.io/commands/DEL nacheinander.
Wenn es einen besseren Weg gibt, lass es mich wissen, ich werde die Antwort aktualisieren.
Beispielimplementierung mit randomkey in Ruby als Rake-Task, ein nicht blockierender Ersatz für etwas wie 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
Es ist einfach über die Funktion "Zweig entfernen" in FastoRedis implementiert. Wählen Sie einfach den Zweig aus, den Sie entfernen möchten.
Bitte benutzen Sie diesen Befehl und versuchen Sie:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
Ich habe die meisten der oben genannten Methoden ausprobiert, aber sie haben bei mir nicht funktioniert. Nach einigen Suchanfragen habe ich folgende Punkte gefunden:
-n [number]
del
aber wenn es Tausende oder Millionen von Schlüsseln sind , ist es besser zu nutzen , unlink
weil unlink ist non-blocking , während del blockiert, für weitere Informationen besuchen Sie diese Seite unlink vs delkeys
sind wie del und blockiertAlso habe ich diesen Code verwendet, um Schlüssel nach Muster zu löschen:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
Atommassenlöschung des armen Mannes?
Vielleicht könnten Sie sie alle so einstellen, dass sie in derselben Sekunde ablaufen - wie einige Minuten in der Zukunft - und dann bis zu diesem Zeitpunkt warten und sie alle gleichzeitig "selbstzerstörend" sehen.
aber ich bin mir nicht sicher, wie atomar das wäre.
Ab sofort können Sie einen Redis-Client verwenden und zuerst SCAN (unterstützt Pattern Matching) durchführen und dann jeden Schlüssel einzeln löschen.
Allerdings gibt es ein Problem auf der offiziellen redis GitHub einen Rüttler-Matching-del zu schaffen hier , es etwas Liebe gehen zu zeigen , wenn Sie es nützlich finden!
Ich unterstütze alle Antworten im Zusammenhang mit einem Tool oder der Ausführung eines Lua-Ausdrucks.
Noch eine Option von meiner Seite:
In unseren Produktions- und Vorproduktionsdatenbanken befinden sich Tausende von Schlüsseln. Von Zeit zu Zeit müssen wir einige Schlüssel löschen (durch eine Maske), nach bestimmten Kriterien ändern usw. Natürlich gibt es keine Möglichkeit, dies manuell über die CLI zu tun, insbesondere mit Sharding (512 logische Datenbank in jeder physischen).
Zu diesem Zweck schreibe ich ein Java-Client-Tool, das all diese Arbeit erledigt. Im Falle des Löschens von Schlüsseln kann das Dienstprogramm sehr einfach sein, nur eine Klasse dort:
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();
}
}
Der folgende Befehl hat bei mir funktioniert.
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
Spring RedisTemplate selbst bietet die Funktionalität. RedissonClient in der neuesten Version hat die Funktion "deleteByPattern" nicht mehr unterstützt.
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
keys
und delete
Methodenaufrufen können neue Schlüssel erscheinen .