Come "SCADERE" la chiave figlio "HSET" in redis?


108

Devo far scadere tutte le chiavi in ​​redis hash, che sono più vecchie di 1 mese.

Risposte:


117

Questo non è possibile , per mantenere Redis semplice .

Disse Antirez, creatore di Redis:

Salve, non è possibile, utilizzare una chiave di primo livello diversa per quel campo specifico o memorizzare insieme al campo un altro campo con una scadenza, recuperarli entrambi e lasciare che l'applicazione capisca se è ancora valido o non basato su ora attuale.


8
questo è il motivo per cui redis è un software così straordinario. sanno dove mantenerlo semplice
tObi il

20

Redis non supporta TTLhash diversi dalla chiave in alto, che farebbero scadere l'intero hash. Se stai usando un cluster sharded, c'è un altro approccio che potresti usare. Questo approccio potrebbe non essere utile in tutti gli scenari e le caratteristiche delle prestazioni potrebbero differire da quelle previste. Vale ancora la pena menzionare:

Quando si ha un hash, la struttura sostanzialmente assomiglia a:

hash_top_key
  - child_key_1 -> some_value
  - child_key_2 -> some_value
  ...
  - child_key_n -> some_value

Dato che vogliamo aggiungere TTLalle chiavi figlio, possiamo spostarle nelle chiavi superiori. Il punto principale è che la chiave ora dovrebbe essere una combinazione di hash_top_keye chiave figlio:

{hash_top_key}child_key_1 -> some_value
{hash_top_key}child_key_2 -> some_value
...
{hash_top_key}child_key_n -> some_value

Stiamo usando la {}notazione apposta. Ciò consente a tutte quelle chiavi di cadere nella stessa hash slot. Puoi leggere di più al riguardo qui: https://redis.io/topics/cluster-tutorial

Ora se vogliamo fare la stessa operazione di hash, potremmo fare:

HDEL hash_top_key child_key_1 => DEL {hash_top_key}child_key_1

HGET hash_top_key child_key_1 => GET {hash_top_key}child_key_1

HSET hash_top_key child_key_1 some_value => SET {hash_top_key}child_key_1 some_value [some_TTL]

HGETALL hash_top_key => 
  keyslot = CLUSTER KEYSLOT {hash_top_key}
  keys = CLUSTER GETKEYSINSLOT keyslot n
  MGET keys

Quello interessante qui è HGETALL. Per prima cosa otteniamo le hash slotchiavi di tutti i nostri figli. Quindi otteniamo le chiavi per quel particolare hash slote infine recuperiamo i valori. Dobbiamo stare attenti qui poiché potrebbero esserci più di nchiavi per quello hash slote potrebbero anche esserci chiavi a cui non siamo interessati ma hanno lo stesso hash slot. Potremmo effettivamente scrivere uno Luascript per eseguire questi passaggi nel server eseguendo un comando EVALo EVALSHA. Ancora una volta, è necessario prendere in considerazione le prestazioni di questo approccio per il proprio scenario particolare.

Qualche altro riferimento:


Questo approccio utilizza più memoria rispetto a semplici chiavi con tempo di scadenza.
VasileM,

3

Esiste un framework Java Redisson che implementa Mapoggetti hash con supporto TTL di ingresso. Usa hmape zsetRedis oggetti sotto il cofano. Esempio di utilizzo:

RMapCache<Integer, String> map = redisson.getMapCache('map');
map.put(1, 30, TimeUnit.DAYS); // this entry expires in 30 days

Questo approccio è molto utile.


ma come si crea una mappa? perché non trovo alcun tutorial o un metodo di creazione / impostazione
FaNaT

@ ZoltánNémeth In Redis mappa creata automaticamente all'inserimento del primo valore.
Nikita Koksharov

3

Questo è possibile in KeyDB che è un fork di Redis. Poiché è una forcella è completamente compatibile con Redis e funziona come una sostituzione.

Usa semplicemente il comando EXPIREMEMBER. Funziona con set, hash e set ordinati.

EXPIREMEMBER sottochiave nome chiave [ora]

Puoi anche usare TTL e PTTL per vedere la scadenza

Sottochiave nome chiave TTL

Ulteriore documentazione è disponibile qui: https://docs.keydb.dev/docs/commands/#expiremember


2

Per quanto riguarda un'implementazione di NodeJS, ho aggiunto un expiryTimecampo personalizzato nell'oggetto che salvo nell'HASH. Quindi, dopo un periodo di tempo specifico, cancello le voci HASH scadute utilizzando il seguente codice:

client.hgetall(HASH_NAME, function(err, reply) {
    if (reply) {
        Object.keys(reply).forEach(key => {
            if (reply[key] && JSON.parse(reply[key]).expiryTime < (new Date).getTime()) {
                client.hdel(HASH_NAME, key);
            }
        })
    }
});

Puoi renderlo più efficiente usando Array.filterper creare un array di keysper eliminare dall'hash e poi passarlo a client.hdel(HASH_NAME, ...keys)in una singola chiamata.
doubleharp

const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
doubleharp

1

Puoi. Ecco un esempio.

redis 127.0.0.1:6379> hset key f1 1
(integer) 1
redis 127.0.0.1:6379> hset key f2 2
(integer) 1
redis 127.0.0.1:6379> hvals key
1) "1"
2) "1"
3) "2"
redis 127.0.0.1:6379> expire key 10
(integer) 1
redis 127.0.0.1:6379> hvals key
1) "1"
2) "1"
3) "2"
redis 127.0.0.1:6379> hvals key
1) "1"
2) "1"
3) "2"
redis 127.0.0.1:6379> hvals key

Utilizzare EXPIRE o EXPIREAT comando.

Se vuoi far scadere chiavi specifiche nell'hash più vecchie di 1 mese. Non è possibile. Il comando Redis expire è per tutte le chiavi nell'hash. Se imposti la chiave hash giornaliera, puoi impostare un tempo per le chiavi in ​​cui vivere.

hset key-20140325 f1 1
expire key-20140325 100
hset key-20140325 f1 2

24
Non penso che voglia far scadere tutte le chiavi nell'hash, piuttosto tutte le chiavi nell'hash che sono più vecchie di 1 mese , quindi solo alcune di esse. Quale AFAIK non è possibile.
UpTheCreek

1
IMHO la domanda lascia supporre questo. Quindi Jonathan ottiene +1 da me, perché mi ha aiutato! Grazie!
longliveenduro

come si fanno a scadere "f1" e "f2"?
vgoklani

4
Questo non risponde alla domanda o aiuta affatto. La necessità è far scadere gli elementi nell'hash, non l'hash stesso.
Ron

@UpTheCreek Grazie!
Jonathan Kim

1

Puoi memorizzare chiave / valori in Redis in modo diverso per ottenere ciò, semplicemente aggiungendo un prefisso o uno spazio dei nomi alle tue chiavi quando le memorizzi, ad esempio "hset_"

  • Ottieni una chiave / valore GET hset_keyuguale aHGET hset key

  • Aggiungi una chiave / valore SET hset_key valueuguale aHSET hset key

  • Ottieni tutte le chiavi KEYS hset_*uguali aHGETALL hset

  • Ottieni tutte le vals dovrebbe essere fatto in 2 operazioni, prima ottieni tutte le chiavi KEYS hset_*quindi ottieni il valore per ogni chiave

  • Aggiungi una chiave / valore con TTL o fai scadere che è l'argomento della domanda:

 SET hset_key value
 EXPIRE hset_key

Nota : KEYScercherà la corrispondenza della chiave nell'intero database che potrebbe influire sulle prestazioni, specialmente se si dispone di un database di grandi dimensioni.

Nota:

  • KEYScercherà la corrispondenza della chiave nell'intero database che potrebbe influire sulle prestazioni soprattutto se si dispone di un database di grandi dimensioni. mentre SCAN 0 MATCH hset_*potrebbe essere migliore fintanto che non blocca il server, ma le prestazioni sono comunque un problema in caso di database di grandi dimensioni.

  • È possibile creare un nuovo database per archiviare separatamente queste chiavi che si desidera far scadere, soprattutto se sono piccoli set di chiavi.

Grazie a @DanFarrell che ha evidenziato il problema delle prestazioni relativo a KEYS


1
basta essere consapevoli che questo è un cambiamento significativo alle caratteristiche delle prestazioni
Daniel Farrell

Come! se parli di complessità temporale, tutte queste operazioni hanno la stessa complessità temporale di hashset.. ottieni O (1) imposta O (1) ottieni tutto O (n)
Muhammad Soliman

"considera KEYS come un comando che dovrebbe essere utilizzato solo in ambienti di produzione con estrema cura." redis.io/commands/KEYS . HGETALL è O(n)per il numero di cose nel set, KEYSper il numero di cose nel DB.
Daniel Farrell

è vero, scan 0 match namespace:*potrebbe essere migliore fintanto che non blocca il server
Muhammad Soliman

1
inoltre, separare queste chiavi, se sono di piccole dimensioni, in un database diverso. grazie @DanFarrell
Muhammad Soliman

1

Abbiamo avuto lo stesso problema discusso qui.

Abbiamo un hash Redis, una chiave per le voci hash (coppie nome / valore) e dovevamo mantenere i tempi di scadenza individuali su ogni voce hash.

Lo abbiamo implementato aggiungendo n byte di dati di prefisso contenenti informazioni di scadenza codificate quando scriviamo i valori della voce hash, abbiamo anche impostato la scadenza della chiave nel momento contenuto nel valore che viene scritto.

Quindi, in lettura, decodifichiamo il prefisso e controlliamo la scadenza. Questo è un sovraccarico aggiuntivo, tuttavia, le letture sono ancora O (n) e l'intera chiave scadrà quando l'ultima voce hash è scaduta.


0

È possibile utilizzare le notifiche di Redis Keyspace utilizzando psubscribee "__keyevent@<DB-INDEX>__:expired".

Con ciò, ogni volta che una chiave scadrà, riceverai un messaggio pubblicato sulla tua connessione redis.

Per quanto riguarda la tua domanda fondamentalmente crei una chiave "normale" temporanea utilizzando setun tempo di scadenza in s / ms. Dovrebbe corrispondere al nome della chiave che desideri eliminare nel tuo set.

Poiché la tua chiave temporanea verrà pubblicata sulla tua connessione redis tenendo premuto il tasto "__keyevent@0__:expired"quando è scaduta, puoi facilmente eliminare la tua chiave dal set originale poiché il messaggio avrà il nome della chiave.

Un semplice esempio pratico su quella pagina: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3

doc: https://redis.io/topics/notifications (cerca il flag xE)


0

Puoi utilizzare Sorted Set in redis per ottenere un contenitore TTL con timestamp come punteggio. Ad esempio, ogni volta che si inserisce una stringa di evento nel set, è possibile impostarne il punteggio sull'ora dell'evento. In questo modo puoi ottenere dati di qualsiasi finestra temporale chiamando zrangebyscore "your set name" min-time max-time

Inoltre, possiamo fare scadere utilizzando zremrangebyscore "your set name" min-time max-timeper rimuovere vecchi eventi.

L'unico inconveniente qui è che devi fare le pulizie da un processo esterno per mantenere le dimensioni del set.


-1

Puoi far scadere gli hash Redis facilmente, ad esempio usando python

import redis
conn = redis.Redis('localhost')
conn.hmset("hashed_user", {'name': 'robert', 'age': 32})
conn.expire("hashed_user", 10)

Questo farà scadere tutte le chiavi figlio in hash hashed_user dopo 10 secondi

lo stesso da redis-cli,

127.0.0.1:6379> HMSET testt username wlc password P1pp0 age 34
OK
127.0.0.1:6379> hgetall testt
1) "username"
2) "wlc"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
127.0.0.1:6379> expire testt 10
(integer) 1
127.0.0.1:6379> hgetall testt
1) "username"
2) "wlc"
3) "password"
4) "P1pp0"
5) "age"
6) "34"

dopo 10 secondi

127.0.0.1:6379> hgetall testt
(empty list or set)

7
la domanda riguarda la scadenza del hsetbambino, non il pieno hset.
thangdc94

non risponde alla domanda posta
peteclark3
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.