Nel mio Redis DB ho un certo numero di prefix:<numeric_id>
hash.
A volte voglio eliminarli tutti atomicamente. Come posso farlo senza utilizzare un meccanismo di blocco distribuito?
Nel mio Redis DB ho un certo numero di prefix:<numeric_id>
hash.
A volte voglio eliminarli tutti atomicamente. Come posso farlo senza utilizzare un meccanismo di blocco distribuito?
Risposte:
A partire da redis 2.6.0, è possibile eseguire script lua, che vengono eseguiti atomicamente. Non ne ho mai scritto uno, ma penso che sarebbe simile a questo
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Avvertenza : come dice il documento Redis , a causa delle performance maters, il
keys
comando non dovrebbe essere utilizzato per le normali operazioni di produzione, questo comando è destinato al debug e alle operazioni speciali. leggi di più
Vedi la documentazione 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:*
essere un'operazione fondamentale: /
EVAL "return redis.call('del', 'defaultKey', unpack(redis.call('keys', ARGV[1])))" 0 prefix:*
Eseguire in bash:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
AGGIORNARE
Ok ho capito. Che dire in questo modo: memorizza il prefisso incrementale aggiuntivo corrente e aggiungilo a tutte le tue chiavi. Per esempio:
Hai valori come questo:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
Quando è necessario eliminare i dati, è necessario innanzitutto modificare prefix_actuall (ad esempio impostare prefix_prefix_actuall = 3), quindi l'applicazione scriverà nuovi dati nei prefissi delle chiavi: 3: 1 e prefisso: 3: 2. Quindi puoi tranquillamente prendere i vecchi valori dal prefisso: 2: 1 e prefisso: 2: 2 ed eliminare le vecchie chiavi.
redis-cli KEYS "prefix:*" | xargs --delim='\n' redis-cli DEL
redis-cli -n 3 KEYS "prefix:*" | xargs redis-cli -n 3 DEL
Ecco una versione completamente funzionante e atomica di una cancellazione di caratteri jolly implementata in Lua. Funzionerà molto più velocemente della versione xargs a causa della molta meno rete avanti e indietro, ed è completamente atomico, bloccando qualsiasi altra richiesta contro redis fino al termine. Se vuoi eliminare atomicamente le chiavi su Redis 2.6.0 o versioni successive, questa è sicuramente la strada da percorrere:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
Questa è una versione funzionante dell'idea di @mcdizzle nella sua risposta a questa domanda. Il merito dell'idea è al 100%.
EDIT: Secondo il commento di Kikito di seguito, se hai più chiavi da eliminare rispetto alla memoria libera nel tuo server Redis, ti imbatterai nell'errore "troppi elementi per decomprimere" . In tal caso, eseguire:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Come suggerito da Kikito.
for _,k in ipairs(redis.call('keys', KEYS[1])) do redis.call('del', k) end
unpack
trasforma una tabella in un "elenco di variabili indipendenti" (altre lingue lo chiamano explode
) ma il numero massimo non dipende dalla memoria del sistema; è riparato in lua attraverso la LUAI_MAXSTACK
costante. In Lua 5.1 e LuaJIT sono 8000 e in Lua 5.2 è 100000. L'opzione for loop è consigliata IMO.
EVAL
poiché non specifica in anticipo i tasti su cui opererà. Dovrebbe funzionare su una singola istanza ma non aspettarti che funzioni con Redis Cluster.
Dichiarazione di non responsabilità: la seguente soluzione non fornisce atomicità.
A partire dalla v2.8 vuoi davvero usare il comando SCAN invece di KEYS [1]. Il seguente script Bash mostra l'eliminazione delle chiavi per modello:
#!/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 è un comando pericoloso che può potenzialmente comportare un DoS. Quanto segue è un preventivo dalla sua pagina di documentazione:
Avvertenza: considerare KEYS come un comando che deve essere utilizzato solo in ambienti di produzione con estrema cura. Potrebbe rovinare le prestazioni quando viene eseguito su database di grandi dimensioni. Questo comando è destinato al debug e ad operazioni speciali, come la modifica del layout dello spazio chiavi. Non utilizzare KEYS nel normale codice dell'applicazione. Se stai cercando un modo per trovare le chiavi in un sottoinsieme del tuo spazio delle chiavi, considera l'utilizzo di set.
AGGIORNAMENTO: una fodera per lo stesso effetto di base -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
-n 1
ad ogni redis-cli
invocazione:redis-cli -n 1 --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli -n 1 DEL
Per coloro che avevano problemi ad analizzare altre risposte:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
Sostituisci key:*:pattern
con il tuo modello e inseriscilo in redis-cli
e sei a posto.
Credito da: http://redis.io/commands/del
Sto usando il comando seguente in redis 3.2.8
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
Puoi ottenere ulteriori informazioni relative alla ricerca del modello di chiavi da qui: - https://redis.io/commands/keys . Usa il tuo comodo modello in stile glob secondo i tuoi requisiti come *YOUR_KEY_PREFIX*
o YOUR_KEY_PREFIX??
o qualsiasi altro.
E se qualcuno di voi ha integrato la libreria Redis PHP rispetto alla seguente funzione vi aiuterà.
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);
}
}
Grazie :)
La soluzione di @ mcdizle non funziona, funziona solo per una voce.
Questo funziona per tutte le chiavi con lo stesso prefisso
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
Nota: è necessario sostituire "prefisso" con il prefisso chiave ...
Puoi anche usare questo comando per cancellare le chiavi: -
Supponiamo che ci siano molti tipi di chiavi nel tuo redis come-
Ex- " xyz_category_fpc " qui xyz è un sitename e queste chiavi sono correlate a prodotti e categorie di un sito di e-commerce e generate da FPC.
Se usi questo comando come di seguito-
redis-cli --scan --pattern 'key*' | xargs redis-cli del
O
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Elimina tutte le chiavi come ' xyz_category_fpc ' ( elimina le chiavi 1, 2 e 3). Per cancellare altri tasti numerici 4, 5 e 6 usare ' xyz_product_fpc ' nel comando sopra.
Se desideri eliminare tutto in Redis , segui questi comandi-
Con redis-cli:
Ad esempio: - nella tua shell:
redis-cli flushall
redis-cli flushdb
redis-cli del
non è atomico.
La risposta di @ itamar è ottima, ma l'analisi della risposta non ha funzionato per me, esp. nel caso in cui non ci siano chiavi trovate in una data scansione. Una soluzione forse più semplice, direttamente dalla console:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
Questo utilizza anche SCAN, che è preferibile a KEYS in produzione, ma non è atomico.
Ho appena avuto lo stesso problema. Ho archiviato i dati della sessione per un utente nel formato:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
Pertanto, ogni voce era una coppia chiave-valore separata. Quando la sessione viene distrutta, volevo rimuovere tutti i dati della sessione eliminando le chiavi con il modello session:sessionid:*
, ma redis non ha tale funzione.
Cosa ho fatto: memorizzare i dati della sessione in un hash . Mi basta creare un hash con l'id hash session:sessionid
e poi mi spingo key-x
, key-y
, key-z
in questo hash (ordine non importa a me) e se non ho bisogno che hash più mi basta fare una DEL session:sessionid
e tutti i dati associati a tale hash id è andato. DEL
è atomico e l'accesso ai dati / la scrittura dei dati nell'hash è O (1).
Penso che ciò che potrebbe aiutarti è MULTI / EXEC / DISCARD . Pur non equivalendo al 100% alle transazioni , dovresti essere in grado di isolare le eliminazioni da altri aggiornamenti.
FYI.
redis-cli
keys
(questo usa scan
)Forse devi solo modificare i caratteri maiuscoli.
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
Esegui al prompt di bash
$ ./clear-redis-key.sh key_head_pattern
Altre risposte potrebbero non funzionare se la chiave contiene caratteri speciali, Guide$CLASSMETADATA][1]
ad esempio. Il confezionamento di ogni chiave tra virgolette garantirà che vengano eliminati correttamente:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
Una versione che utilizza SCAN anziché KEYS (come raccomandato per i server di produzione) e --pipe
piuttosto che xargs.
Preferisco pipe su xargs perché è più efficiente e funziona quando le tue chiavi contengono virgolette o altri caratteri speciali che la tua shell cerca e interpreta. La sostituzione regex in questo esempio racchiude la chiave tra virgolette doppie e sfugge a eventuali virgolette doppie all'interno.
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
Questa non è una risposta diretta alla domanda, ma poiché sono arrivato qui quando cercavo le mie risposte, lo condividerò qui.
Se hai decine o centinaia di milioni di chiavi che devi abbinare, le risposte fornite qui causeranno la mancata risposta di Redis per un periodo di tempo significativo (minuti?) E potenzialmente si arresta in modo anomalo a causa del consumo di memoria (assicurati, il salvataggio in background lo farà avviare nel bel mezzo dell'operazione).
L'approccio seguente è innegabilmente brutto, ma non ne ho trovato uno migliore. L'atomicità è fuori discussione qui, in questo caso l'obiettivo principale è mantenere Redis attivo e reattivo il 100% delle volte. Funzionerà perfettamente se hai tutte le tue chiavi in uno dei database e non hai bisogno di abbinare alcun modello, ma non puoi usare http://redis.io/commands/FLUSHDB a causa della sua natura bloccante.
L'idea è semplice: scrivere uno script che viene eseguito in un ciclo e utilizza l'operazione O (1) come http://redis.io/commands/SCAN o http://redis.io/commands/RANDOMKEY per ottenere le chiavi, controlla se abbina il modello (se ne hai bisogno) e http://redis.io/commands/DEL loro uno per uno.
Se esiste un modo migliore per farlo, per favore fatemi sapere, aggiornerò la risposta.
Esempio di implementazione con randomkey in Ruby, come attività di rake, un sostituto non bloccante di qualcosa come 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
È semplice implementato tramite la funzionalità "Rimuovi ramo" in FastoRedis , basta selezionare il ramo che si desidera rimuovere.
Si prega di utilizzare questo comando e provare:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
Ho provato la maggior parte dei metodi sopra menzionati ma non hanno funzionato per me, dopo alcune ricerche ho trovato questi punti:
-n [number]
del
ma se ci sono migliaia o milioni di chiavi è meglio usarle unlink
perché unlink è non bloccante mentre del è bloccato, per maggiori informazioni visita questa pagina unlink vs delkeys
sono come del e sta bloccandoquindi ho usato questo codice per cancellare le chiavi in base al modello:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
Ad oggi, è possibile utilizzare un client redis ed eseguire prima SCAN (supporta la corrispondenza dei modelli) e quindi DEL ogni tasto singolarmente.
Tuttavia, c'è un problema su redis github ufficiale per creare un patter-matching-del qui , vai a mostrarlo un po 'd'amore se lo trovi utile!
Sostengo tutte le risposte relative all'avere qualche strumento o eseguire l'espressione Lua.
Un'altra opzione da parte mia:
Nei nostri database di produzione e pre-produzione ci sono migliaia di chiavi. Di tanto in tanto è necessario eliminare alcune chiavi (con una maschera), modificarle con alcuni criteri, ecc. Naturalmente, non c'è modo di farlo manualmente dalla CLI, specialmente se si ha lo sharding (512 dbs logici in ogni fisico).
A questo scopo scrivo lo strumento client Java che fa tutto questo lavoro. In caso di cancellazione delle chiavi l'utilità può essere molto semplice, solo una classe lì:
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();
}
}
Sotto il comando ha funzionato per me.
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
Spring RedisTemplate stesso fornisce la funzionalità. RedissonClient nell'ultima versione ha deprecato la funzionalità "deleteByPattern".
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
keys
e delete
invocazioni di metodi.