Wie kann ich den untergeordneten Schlüssel "HSET" in redis "ablaufen" lassen?


107

Ich muss alle Schlüssel in Redis Hash ablaufen lassen, die älter als 1 Monat sind.

Antworten:


117

Dies ist nicht möglich , um Redis einfach zu halten .

Quoth Antirez, Schöpfer von Redis:

Hallo, es ist nicht möglich, entweder einen anderen Schlüssel der obersten Ebene für dieses bestimmte Feld zu verwenden oder zusammen mit dem abgelegten anderen Feld mit einer Ablaufzeit zu speichern, beide abzurufen und der Anwendung zu erklären, ob sie noch gültig ist oder nicht aktuelle Uhrzeit.


7
Aus diesem Grund ist Redis eine großartige Software. Sie wissen, wo sie es einfach halten können
bis zum

20

Redis unterstützt es nicht, TTLandere Hashes als den oberen Schlüssel zu verwenden, wodurch der gesamte Hash abläuft. Wenn Sie einen Sharded-Cluster verwenden, können Sie einen anderen Ansatz verwenden. Dieser Ansatz ist möglicherweise nicht in allen Szenarien nützlich, und die Leistungsmerkmale können von den erwarteten abweichen. Noch erwähnenswert:

Wenn Sie einen Hash haben, sieht die Struktur im Grunde so aus:

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

Da wir die untergeordneten TTLSchlüssel hinzufügen möchten , können wir sie in die oberen Schlüssel verschieben. Der Hauptpunkt ist, dass der Schlüssel jetzt eine Kombination aus einem hash_top_keyuntergeordneten Schlüssel sein sollte:

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

Wir verwenden die {}Notation absichtlich. Dadurch können alle diese Schlüssel in dieselbe fallen hash slot. Weitere Informationen finden Sie hier: https://redis.io/topics/cluster-tutorial

Wenn wir nun die gleiche Operation von Hashes ausführen möchten, können wir Folgendes tun:

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

Das Interessante hier ist HGETALL. Zuerst bekommen wir die hash slotSchlüssel für alle unsere Kinder. Dann bekommen wir die Schlüssel für diesen bestimmten hash slotund schließlich rufen wir die Werte ab. Wir müssen hier vorsichtig sein, da es dafür mehr als nur nSchlüssel geben kann hash slotund es auch Schlüssel geben kann, an denen wir nicht interessiert sind, die aber dieselben haben hash slot. Wir könnten tatsächlich ein LuaSkript schreiben , um diese Schritte auf dem Server auszuführen, indem wir einen Befehl EVALoder ausführen EVALSHA. Auch hier müssen Sie die Leistung dieses Ansatzes für Ihr spezielles Szenario berücksichtigen.

Einige weitere Referenzen:


Dieser Ansatz verwendet mehr Speicher als einfache Schlüssel mit Ablaufzeit.
VasileM

3

Es gibt ein Redisson- Java-Framework, das Hash- MapObjekte mit TTL-Unterstützung für Einträge implementiert . Es verwendet hmapund zsetRedis Objekte unter der Haube. Anwendungsbeispiel:

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

Dieser Ansatz ist sehr nützlich.


aber wie kann man eine karte erstellen? weil ich kein Tutorial oder eine Methode zum Erstellen /
Festlegen finde

@ ZoltánNémeth In Redis wird die Karte automatisch erstellt, wenn der erste Wert eingefügt wird.
Nikita Koksharov

3

Dies ist in KeyDB möglich, einer Fork of Redis. Da es sich um eine Gabel handelt, ist sie vollständig mit Redis kompatibel und fungiert als Ersatz.

Verwenden Sie einfach den Befehl EXPIREMEMBER. Es funktioniert mit Sets, Hashes und sortierten Sets.

EXPIREMEMBER-Keyname-Unterschlüssel [Zeit]

Sie können auch TTL und PTTL verwenden, um den Ablauf anzuzeigen

TTL-Keyname-Unterschlüssel

Weitere Dokumentation finden Sie hier: https://docs.keydb.dev/docs/commands/#expiremember


2

In Bezug auf eine NodeJS-Implementierung habe ich expiryTimedem Objekt, das ich im HASH speichere, ein benutzerdefiniertes Feld hinzugefügt. Nach einer bestimmten Zeit lösche ich die abgelaufenen HASH-Einträge mit dem folgenden Code:

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

Sie können dies effizienter gestalten, indem Sie Array.filterein Array keyszum Löschen aus dem Hash erstellen und dieses dann client.hdel(HASH_NAME, ...keys)in einem einzigen Aufruf an übergeben.
Doublesharp

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

1

Sie können. Hier ist ein Beispiel.

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

Verwenden Sie den Befehl EXPIRE oder EXPIREAT .

Wenn Sie bestimmte Schlüssel im Hash ablaufen lassen möchten, die älter als 1 Monat sind. Das ist nicht möglich. Der Redis Expire-Befehl gilt für alle Schlüssel im Hash. Wenn Sie den täglichen Hash-Schlüssel festlegen, können Sie die Lebensdauer der Schlüssel festlegen.

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

24
Ich glaube nicht, dass er alle Schlüssel im Hash ablaufen lassen möchte , sondern alle Schlüssel im Hash, die älter als 1 Monat sind , also nur einige von ihnen. Welche AFAIK ist nicht möglich.
UpTheCreek

1
IMHO die Frage lassen Sie uns dies annehmen. Also bekommt Jonathan +1 von mir, weil er mir geholfen hat! Danke!
Longliveenduro

Wie verfallen "f1" und "f2"?
Vgoklani

4
Dies beantwortet die Frage nicht oder hilft überhaupt nicht. Die Notwendigkeit besteht darin, die Elemente im Hash abzulaufen, nicht den Hash selbst.
Ron

@UpTheCreek Danke!
Jonathan Kim

1

Sie können Schlüssel / Werte in Redis anders speichern, um dies zu erreichen, indem Sie Ihren Schlüsseln einfach ein Präfix oder einen Namespace hinzufügen, wenn Sie sie speichern, z. B. "hset_".

  • Holen Sie sich einen Schlüssel / Wert GET hset_keygleichHGET hset key

  • Fügen Sie einen Schlüssel / Wert hinzu, der SET hset_key valuegleich istHSET hset key

  • Holen Sie sich alle Schlüssel KEYS hset_*gleichHGETALL hset

  • Das Abrufen aller Werte sollte in 2 Operationen erfolgen. Holen Sie sich zuerst alle Schlüssel und KEYS hset_*dann den Wert für jeden Schlüssel

  • Fügen Sie mit TTL einen Schlüssel / Wert hinzu oder verfallen, was das Thema der Frage ist:

 SET hset_key value
 EXPIRE hset_key

Hinweis : KEYSSucht nach Übereinstimmungen mit dem Schlüssel in der gesamten Datenbank, was sich auf die Leistung auswirken kann, insbesondere wenn Sie über eine große Datenbank verfügen.

Hinweis:

  • KEYSsucht nach Übereinstimmungen mit dem Schlüssel in der gesamten Datenbank, was sich auf die Leistung auswirken kann, insbesondere wenn Sie über eine große Datenbank verfügen. Dies ist SCAN 0 MATCH hset_*möglicherweise besser, solange der Server nicht blockiert wird, die Leistung jedoch bei großen Datenbanken ein Problem darstellt.

  • Sie können eine neue Datenbank erstellen, um diese Schlüssel, die Sie ablaufen lassen möchten, separat zu speichern, insbesondere wenn es sich um kleine Schlüsselsätze handelt.

Vielen Dank an @DanFarrell, der das Leistungsproblem im Zusammenhang mit hervorgehoben hat KEYS


1
Seien Sie sich nur bewusst, dass dies eine signifikante Änderung der Leistungsmerkmale ist
Daniel Farrell

Wie! Wenn Sie über Zeitkomplexitäten sprechen, haben alle diese Operationen die gleiche Zeitkomplexität wie hashset.. get O (1) set O (1) get all O (n)
Muhammad Soliman

"Betrachten Sie KEYS als einen Befehl, der nur in Produktionsumgebungen mit äußerster Sorgfalt verwendet werden sollte." redis.io/commands/KEYS . HGETALL steht O(n)für die Anzahl der Dinge in der Menge und KEYSfür die Anzahl der Dinge in der Datenbank .
Daniel Farrell

Das ist wahr, scan 0 match namespace:*könnte besser sein, solange es den Server nicht blockiert
Muhammad Soliman

1
Trennen Sie diese Schlüssel auch, wenn sie klein sind, in eine andere Datenbank. danke @DanFarrell
Muhammad Soliman

1

Wir hatten das gleiche Problem hier diskutiert.

Wir haben einen Redis-Hash, einen Schlüssel für Hash-Einträge (Name / Wert-Paare), und wir mussten für jeden Hash-Eintrag individuelle Ablaufzeiten festlegen.

Wir haben dies implementiert, indem wir beim Schreiben der Hash-Eintragswerte n Bytes Präfixdaten hinzugefügt haben, die codierte Ablaufinformationen enthalten. Außerdem haben wir den Schlüssel so festgelegt, dass er zu dem Zeitpunkt abläuft, der in dem zu schreibenden Wert enthalten ist.

Dann dekodieren wir beim Lesen das Präfix und prüfen, ob es abgelaufen ist. Dies ist ein zusätzlicher Aufwand, die Lesevorgänge sind jedoch immer noch O (n) und der gesamte Schlüssel läuft ab, wenn der letzte Hash-Eintrag abgelaufen ist.


0

Sie können die Redis Keyspace-Benachrichtigungen mit psubscribeund verwenden "__keyevent@<DB-INDEX>__:expired".

Damit erhalten Sie jedes Mal, wenn ein Schlüssel abläuft, eine Nachricht, die auf Ihrer Redis-Verbindung veröffentlicht wird.

In Bezug auf Ihre Frage erstellen Sie im Grunde einen temporären "normalen" Schlüssel setmit einer Ablaufzeit in s / ms. Es sollte mit dem Namen des Schlüssels übereinstimmen, den Sie in Ihrem Set löschen möchten.

Da Ihr temporärer Schlüssel in Ihrer Redis-Verbindung veröffentlicht wird, "__keyevent@0__:expired"wenn er abgelaufen ist, können Sie Ihren Schlüssel einfach aus Ihrem ursprünglichen Satz löschen, da die Nachricht den Namen des Schlüssels enthält.

Ein einfaches Beispiel in der Praxis auf dieser Seite: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3

doc: https://redis.io/topics/notifications (achten Sie auf das Flag xE)


0

Sie können Sorted Set in redis verwenden, um einen TTL-Container mit Zeitstempel als Punktzahl zu erhalten. Wenn Sie beispielsweise eine Ereigniszeichenfolge in den Satz einfügen, können Sie die Punktzahl auf die Ereigniszeit festlegen. So können Sie durch Aufrufen Daten aus jedem Zeitfenster abrufen zrangebyscore "your set name" min-time max-time

Darüber hinaus können wir verfallen, indem wir zremrangebyscore "your set name" min-time max-timealte Ereignisse entfernen.

Der einzige Nachteil hierbei ist, dass Sie die Reinigung von einem Außenstehenden durchführen müssen, um die Größe des Sets beizubehalten.


-1

Sie können Redis-Hashes problemlos ablaufen lassen , z. B. mit Python

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

Dadurch laufen alle untergeordneten Schlüssel in hash hashed_user nach 10 Sekunden ab

das gleiche von 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"

nach 10 Sekunden

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

6
Frage ist über abgelaufene hsetKind nicht die volle hset.
thangdc94

beantwortet die gestellte Frage nicht
peteclark3
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.