Comment «EXPIRER» la clé enfant «HSET» dans Redis?


108

J'ai besoin d'expirer toutes les clés du hachage redis, qui datent de plus d'un mois.

Réponses:


117

Ce n'est pas possible , dans un souci de simplification de Redis .

Quoth Antirez, créateur de Redis:

Bonjour, il n'est pas possible d'utiliser une clé de niveau supérieur différente pour ce champ spécifique, ou de stocker avec le champ un autre champ avec une heure d'expiration, de récupérer les deux et de laisser l'application comprendre si elle est toujours valide ou non basée sur heure actuelle.


8
c'est pourquoi redis est un logiciel si génial. ils savent où faire simple
tObi

20

Redis ne prend pas en charge TTLles hachages autres que la clé supérieure, qui expirerait tout le hachage. Si vous utilisez un cluster partitionné, vous pouvez utiliser une autre approche. Cette approche ne peut pas être utile dans tous les scénarios et les caractéristiques de performance peuvent différer de celles attendues. Encore à mentionner:

Lors d'un hachage, la structure ressemble essentiellement à:

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

Puisque nous voulons ajouter TTLaux clés enfants, nous pouvons les déplacer vers les clés supérieures. Le point principal est que la clé doit maintenant être une combinaison de hash_top_keyet de clé enfant:

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

Nous utilisons la {}notation à dessein. Cela permet à toutes ces clés de tomber dans le même hash slot. Vous pouvez en savoir plus ici: https://redis.io/topics/cluster-tutorial

Maintenant, si nous voulons faire la même opération de hachage, nous pourrions faire:

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

L'intéressant ici est HGETALL. Nous obtenons hash slotd'abord les clés de tous nos enfants. Ensuite, nous obtenons les clés pour cela hash slotet enfin nous récupérons les valeurs. Nous devons faire attention ici car il pourrait y avoir plus que des nclés pour cela hash slotet aussi il pourrait y avoir des clés qui ne nous intéressent pas, mais elles ont les mêmes hash slot. Nous pourrions en fait écrire un Luascript pour effectuer ces étapes sur le serveur en exécutant une commande EVALou EVALSHA. Encore une fois, vous devez prendre en considération les performances de cette approche pour votre scénario particulier.

Quelques références supplémentaires:


Cette approche utilise plus de mémoire que de simples clés avec un délai d'expiration.
VasileM

3

Il existe un framework Java Redisson qui implémente un Mapobjet de hachage avec prise en charge de l'entrée TTL. Il utilise des objets hmapet zsetRedis sous le capot. Exemple d'utilisation:

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

Cette approche est très utile.


mais comment pouvez-vous créer une carte? car je ne trouve pas de tutoriel ni de méthode de création / définition
FaNaT

@ ZoltánNémeth Dans Redis, la carte est créée automatiquement lors de l'insertion de la première valeur.
Nikita Koksharov

3

Ceci est possible dans KeyDB qui est un Fork de Redis. Parce que c'est une fourche, elle est entièrement compatible avec Redis et fonctionne comme un remplacement.

Utilisez simplement la commande EXPIREMEMBER. Il fonctionne avec des ensembles, des hachages et des ensembles triés.

EXPIREMEMBER keyname sous-clé [heure]

Vous pouvez également utiliser TTL et PTTL pour voir l'expiration

Sous-clé de nom de clé TTL

Plus de documentation est disponible ici: https://docs.keydb.dev/docs/commands/#expiremember


2

Concernant une implémentation NodeJS, j'ai ajouté un expiryTimechamp personnalisé dans l'objet que je sauvegarde dans le HASH. Ensuite, après une période spécifique, j'efface les entrées HASH expirées en utilisant le code suivant:

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

Vous pouvez rendre cela plus efficace en utilisant Array.filterpour créer un tableau de keysà supprimer du hachage, puis le transmettre client.hdel(HASH_NAME, ...keys)en un seul appel.
doublesharp

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

1

Vous pouvez. Voici un exemple.

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

Utilisez EXPIRATION ou EXPIREAT commande.

Si vous souhaitez faire expirer des clés spécifiques dans le hachage, plus de 1 mois. Ce n'est pas possible. La commande Redis expire concerne toutes les clés du hachage. Si vous définissez une clé de hachage quotidienne, vous pouvez définir une durée de vie des clés.

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

24
Je ne pense pas qu'il veuille faire expirer toutes les clés du hachage, mais plutôt toutes les clés du hachage qui datent de plus d'un mois , donc seulement certaines d'entre elles. Quel AFAIK n'est pas possible.
UpTheCreek

1
IMHO la question laissez-nous supposer cela. Alors Jonathan obtient +1 de moi, car il m'a aidé! Merci!
longliveenduro

comment expirez-vous "f1" et "f2"?
vgoklani

4
Cela ne répond pas à la question ou n'aide pas du tout. Le besoin est d'expirer les éléments du hachage, pas le hachage lui-même.
Ron

@UpTheCreek Merci!
Jonathan Kim

1

Vous pouvez stocker les clés / valeurs dans Redis différemment pour y parvenir, en ajoutant simplement un préfixe ou un espace de noms à vos clés lorsque vous les stockez, par exemple "hset_"

  • Obtenir une clé / valeur GET hset_keyégale àHGET hset key

  • Ajouter une clé / valeur SET hset_key valueégale àHSET hset key

  • Obtenez toutes les clés KEYS hset_*égales àHGETALL hset

  • Obtenir toutes les valeurs doit être effectué en 2 opérations, obtenir d'abord toutes les clés, KEYS hset_*puis obtenir la valeur de chaque clé

  • Ajoutez une clé / valeur avec TTL ou expirez qui est le sujet de la question:

 SET hset_key value
 EXPIRE hset_key

Remarque : KEYSrecherchera la correspondance de la clé dans toute la base de données, ce qui peut affecter les performances, en particulier si vous avez une grande base de données.

Remarque:

  • KEYSrecherchera la correspondance de la clé dans toute la base de données, ce qui peut affecter les performances, en particulier si vous avez une grande base de données. alors SCAN 0 MATCH hset_*peut - être mieux aussi longtemps qu'il ne bloque pas le serveur mais la performance est un problème dans le cas de la grande base de données.

  • Vous pouvez créer une nouvelle base de données pour stocker séparément ces clés que vous souhaitez expirer, surtout s'il s'agit d'un petit jeu de clés.

Merci à @DanFarrell qui a souligné le problème de performance lié à KEYS


1
sachez simplement qu'il s'agit d'un changement significatif des caractéristiques de performance
Daniel Farrell

Comment! si vous parlez de complexités temporelles, toutes ces opérations ont la même complexité temporelle que hashset.. get O (1) set O (1) get all O (n)
Muhammad Soliman

"considérez KEYS comme une commande qui ne doit être utilisée qu'avec un soin extrême dans les environnements de production." redis.io/commands/KEYS . HGETALL est O(n)pour le nombre de choses dans l'ensemble, KEYSpour le nombre de choses dans la DB.
Daniel Farrell

c'est vrai, cela scan 0 match namespace:*pourrait être mieux tant que cela ne bloque pas le serveur
Muhammad Soliman

1
également, séparez ces clés, si elles sont de petite taille, dans une base de données différente. merci @DanFarrell
Muhammad Soliman

1

Nous avons eu le même problème discuté ici.

Nous avons un hachage Redis, une clé pour les entrées de hachage (paires nom / valeur), et nous devions conserver des délais d'expiration individuels pour chaque entrée de hachage.

Nous avons implémenté cela en ajoutant n octets de données de préfixe contenant des informations d'expiration codées lorsque nous écrivons les valeurs d'entrée de hachage, nous définissons également la clé pour qu'elle expire au moment contenu dans la valeur en cours d'écriture.

Ensuite, en lecture, nous décodons le préfixe et vérifions l'expiration. Il s'agit d'une surcharge supplémentaire, cependant, les lectures sont toujours O (n) et la clé entière expirera lorsque la dernière entrée de hachage aura expiré.


0

Vous pouvez utiliser les notifications de l'espace clé Redis en utilisant psubscribeet "__keyevent@<DB-INDEX>__:expired".

Avec cela, chaque fois qu'une clé expirera, vous recevrez un message publié sur votre connexion redis.

En ce qui concerne votre question, vous créez une clé temporaire "normale" en utilisant setun délai d'expiration en s / ms. Il doit correspondre au nom de la clé que vous souhaitez supprimer de votre ensemble.

Comme votre clé temporaire sera publiée sur votre connexion redis en tenant le "__keyevent@0__:expired"quand elle a expiré, vous pouvez facilement supprimer votre clé de votre jeu d'origine car le message aura le nom de la clé.

Un exemple simple en pratique sur cette page: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3

doc: https://redis.io/topics/notifications (recherchez le drapeau xE)


0

Vous pouvez utiliser Sorted Set dans redis pour obtenir un conteneur TTL avec horodatage comme score. Par exemple, chaque fois que vous insérez une chaîne d'événement dans l'ensemble, vous pouvez définir son score sur l'heure de l'événement. Ainsi, vous pouvez obtenir des données de n'importe quelle fenêtre de temps en appelant zrangebyscore "your set name" min-time max-time

De plus, nous pouvons faire expirer en utilisant zremrangebyscore "your set name" min-time max-timepour supprimer les anciens événements.

Le seul inconvénient ici est que vous devez faire le ménage à partir d'un processus externe pour maintenir la taille de l'ensemble.


-1

Vous pouvez facilement expirer les hachages Redis, par exemple en utilisant python

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

Cela expirera toutes les clés enfants dans hash hashed_user après 10 secondes

idem de 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"

après 10 secondes

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

7
question porte sur expirer l' hsetenfant pas le plein hset.
thangdc94

ne répond pas à la question posée
peteclark3
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.