Come eliminare in modo atomico le chiavi che corrispondono a un modello utilizzando Redis

StackOverflow https://stackoverflow.com/questions/4006324

  •  25-09-2019
  •  | 
  •  

Domanda

Nel mio DB Redis ne ho diversi prefix:<numeric_id> hash.

A volte vorrei eliminarli tutti atomicamente.Come posso farlo senza utilizzare un meccanismo di blocco distribuito?

È stato utile?

Soluzione

A partire da redis 2.6.0, è possibile eseguire script lua, che vengono eseguiti in modo atomico.Non ne ho mai scritto uno, ma penso che sarebbe qualcosa del genere

EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]

Vedi il Documentazione VALUTAZIONE.

Altri suggerimenti

Esegui in bash:

redis-cli KEYS "prefix:*" | xargs redis-cli DEL

Aggiorna

Ok, ho capito. Che dire in questo modo: attuale del serbatoio prefisso incrementale aggiuntivo e aggiungerlo a tutte le vostre chiavi. Ad esempio:

Hai valori in questo modo:

prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10

Quando è necessario i dati di spurgo, si cambia prefix_actuall prima (ad esempio set prefix_prefix_actuall = 3), quindi l'applicazione scriverà nuovi dati chiavi prefisso: 3: 1 e il prefisso: 3: 2. Poi si può tranquillamente prendere i vecchi valori da prefisso: 2: 1 e il prefisso: 2:. 2 e spurgare vecchie chiavi

Ecco una versione completamente funzionante e atomica di un jolly delete implementato in Lua. Sarà molto più veloce rispetto alla versione xargs a causa di molto avanti e indietro meno della rete, ed è completamente atomica, bloccando eventuali altre richieste contro Redis finché finisce. Se si vuole chiavi atomicamente cancellazione su Redis 2.6.0 o superiore, questo è 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. Credito per l'idea del 100% va a lui.

Modifica Commento di Per Kikito qui sotto, se si dispone di più chiavi per eliminare di memoria libera nel server Redis, si incorrerà in "troppi elementi per disfare" errore . In tal caso, fare:

for _,k in ipairs(redis.call('keys', ARGV[1])) do 
    redis.call('del', k) 
end

Come Kikito suggerito.

Disclaimer:la seguente soluzione no fornire atomicità.

A partire dalla v2.8 tu Veramente desidera utilizzare il SCANSIONE comando invece di KEYS[1].Il seguente script Bash mostra l'eliminazione delle chiavi in ​​base al 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] CHIAVI è un comando pericoloso che può potenzialmente provocare un DoS.Quella che segue è una citazione dalla sua pagina di documentazione:

Avvertimento: considerare i TASTI come un comando da utilizzare solo in ambienti di produzione con estrema cautela.Potrebbe compromettere le prestazioni quando viene eseguito su database di grandi dimensioni.Questo comando è destinato al debugging e a operazioni speciali, come la modifica del layout dello spazio delle chiavi.Non utilizzare CHIAVI 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 dei set.

AGGIORNAMENTO: una riga per lo stesso effetto di base -

$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL

Per coloro che sono stati problemi a parsing altre risposte:

eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0

Sostituire key:*:pattern con il vostro proprio modello ed entrare in questo in redis-cli e siete a posto.

LISCO di credito da: http://redis.io/commands/del

sto usando qui sotto comando nel Redis 3.2.8

redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL

È possibile ottenere ulteriori informazioni relative alle chiavi di ricerca modello da qui: - https://redis.io/commands/ chiavi . Usate il vostro comodo modello di glob stile secondo il vostro requisito come *YOUR_KEY_PREFIX* o YOUR_KEY_PREFIX?? o qualsiasi altro.

E se qualcuno di voi ha integrato biblioteca Redis PHP che sotto 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:)

@ di mcdizle soluzione non funziona funziona solo per una voce.

Questo funziona per tutti i tasti 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 la vostra chiave di prefisso ...

Puoi anche usare questo comando per eliminare le chiavi: -

Supponiamo che ci siano molti tipi di chiavi nel tuo Redis come-

  1. 'xyz_categoria_fpc_12'
  2. 'xyz_categoria_fpc_245'
  3. 'xyz_categoria_fpc_321'
  4. 'xyz_prodotto_fpc_876'
  5. 'xyz_prodotto_fpc_302'
  6. 'xyz_prodotto_fpc_01232'

Ex-'xyz_categoria_fpc' Qui xyz è un nome del sito, e queste chiavi sono relative 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

Cancella tutti i tasti come 'xyz_categoria_fpc' (elimina i tasti 1, 2 e 3).Per eliminare altri tasti numerici 4, 5 e 6 utilizzare 'xyz_prodotto_fpc' nel comando precedente.

Se lo desidera Elimina tutto In Redis, quindi segui questi comandi-

Con redis-cli:

  1. FLUSHDB - Rimuove i dati dal database CORRENTE della tua connessione.
  2. FLUSHALL - Rimuove i dati da TUTTI i database.

Ad esempio: - nella tua shell:

redis-cli flushall
redis-cli flushdb

Se si dispone di spazio nel nome delle chiavi, è possibile utilizzare questo in bash:

redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del

@ di Itamar risposta è grande, ma l'analisi della risposta non funzionava per me, esp. nel caso in cui non ci sono tasti che si trovano in una determinata 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 KEYS in produzione, ma non è atomica.

Ho appena avuto lo stesso problema. Ho memorizzato 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

Quindi, ogni voce è stata una coppia chiave-valore separato. Quando la sessione viene distrutta, ho voluto rimuovere tutti i dati della sessione eliminando i tasti con il session:sessionid:* modello -. Ma Redis non ha una tale funzione

Quello che ho fatto: memorizzare i dati della sessione in un hash . Mi basta creare un hash con l'id hash di session:sessionid e poi mi spingo key-x, key-y, key-z a tale 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 / scrittura dei dati l'hash è O (1).

FYI.

  • solo con bash e redis-cli
  • non utilizza keys (Questo utilizza scan)
  • funziona bene in modalità cluster
  • non atomica

Forse avete solo bisogno di modificare i caratteri di capitale.

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 in bash prompt dei

$ ./clear-redis-key.sh key_head_pattern

Penso che quello che potrebbe aiutare voi è la MULTI / EXEC / DISCARD . Anche se non 100% equivalente delle transazioni, è dovrebbe essere in grado di isolare le eliminazioni da altri aggiornamenti.

E 'semplice implementato tramite la funzionalità "Rimuovi ramo" in FastoRedis , basta selezionare ramo che si desidera rimuovere.

entrare descrizione dell'immagine qui

Si prega di utilizzare questo comando e provare:

redis-cli --raw keys "$PATTERN" | xargs redis-cli del

Una versione con SCAN piuttosto che CHIAVI (come consigliato per i server di produzione) e --pipe piuttosto che xargs.

Io preferisco pipe xargs perché è più efficiente e funziona quando le chiavi contengono virgolette o altri caratteri speciali che la shell con prova e interpretare. La sostituzione regex in questo esempio avvolge la chiave tra virgolette, e sfugge a qualsiasi 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 mentre cercavo le mie risposte, la condividerò qui.

Se hai decine o centinaia di milioni di chiavi da abbinare, le risposte fornite qui faranno sì che Redis non risponda per un periodo di tempo significativo (minuti?) e potenzialmente si blocchi a causa del consumo di memoria (assicurati che il salvataggio in background entrare nel mezzo dell'operazione).

Il seguente approccio è 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 chiavi in ​​uno dei database e non hai bisogno di abbinare alcun modello, ma non puoi usarlo 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 corrispondono allo schema (se ne hai bisogno) e http://redis.io/commands/DEL loro uno per uno.

Se c'è un modo migliore per farlo, per favore fatemelo sapere, aggiornerò la risposta.

Esempio di implementazione con randomkey in Ruby, come attività rake, un sostituto non bloccante di qualcosa di simile 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

Ho provato la maggior parte dei metodi di cui sopra, ma non ha funzionato per me, dopo alcune ricerche ho trovato questi punti:

  • se si dispone di più di un db su Redis è necessario determinare il database utilizzando -n [number]
  • se si dispone di un paio di tasti utilizzano del ma se ci sono migliaia o milioni di chiavi è meglio usare unlink perché Scollega è non bloccante , mentre del sta bloccando, per maggiori informazioni visita questa pagina < a href = "https://stackoverflow.com/questions/45818371/is-the-unlink-command-always-better-than-del-command"> Scollega vs del
  • anche keys sono come del e sta bloccando

quindi ho usato questo codice per chiavi di cancellazione dal testo:

 redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink 

Sono favorevole tutte le risposte relative ad avere qualche strumento o eseguire espressione Lua.

Una possibilità più da parte mia:

Nel nostro database di produzione e pre-produzione ci sono migliaia di chiavi. Di volta in volta abbiamo bisogno di eliminare alcune chiavi (da parte di alcuni maschera), modificare da parte di alcuni criteri, ecc Naturalmente, non c'è modo di farlo manualmente da CLI, soprattutto avendo sharding (512 DBS logiche in ogni fisico).

Per questo strumento client java scrittura scopo io che fa tutto questo lavoro. In caso di eliminazione le chiavi di utilità può essere molto semplice, una sola classe c'è:

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();
    }

}

Di seguito il comando ha funzionato per me.

redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL

annuncio di oggi, è possibile utilizzare un client Redis e eseguire la scansione primi supporti (pattern matching) e poi DEL ogni tasto singolarmente.

Tuttavia, v'è un problema su github ufficiale Redis per creare un patter-matching-del qui , go mostrare un po 'di amore, se lo trovate utile!

atomic mass-delete povero?

forse si potrebbe impostare tutti a EXPIREAT lo stesso secondo - come pochi minuti nel futuro -. E poi aspettare fino a quel momento e di vederli tutti "auto-distruzione", allo stesso tempo

, ma io non sono davvero sicuro di come atomica che sarebbe stato.

Primavera RedisTemplate stesso fornisce la funzionalità. RedissonClient nella sua ultima versione ha deprecato la funzionalità "deleteByPattern".

Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top