Jak „EXPIRE” klucza podrzędnego „HSET” w Redis?

108

Muszę wygasnąć wszystkie klucze w skrócie redis, które są starsze niż 1 miesiąc.

aieven
źródło

Odpowiedzi:

117

Nie jest to możliwe ze względu na prostotę obsługi Redis .

Quoth Antirez, twórca Redis:

Cześć, nie jest możliwe, użyj innego klucza najwyższego poziomu dla tego konkretnego pola lub zapisz wraz z polem inne pole z czasem wygaśnięcia, pobierz oba i pozwól aplikacji zrozumieć, czy jest nadal ważny, czy nie jest oparty na Obecny czas.

Supr
źródło
8
dlatego redis jest takim niesamowitym oprogramowaniem. wiedzą, gdzie to
uprościć
20

Redis nie obsługuje TTLhaszów innych niż górny klucz, co spowodowałoby wygaśnięcie całego skrótu. Jeśli używasz podzielonego na fragmenty klastra, możesz zastosować inne podejście. To podejście nie może być przydatne we wszystkich scenariuszach, a charakterystyki wydajności mogą różnić się od oczekiwanych. Nadal warto wspomnieć:

W przypadku skrótu struktura zasadniczo wygląda następująco:

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

Ponieważ chcemy dodać TTLklucze podrzędne, możemy przenieść je do kluczy górnych. Najważniejsze jest to, że klucz powinien być teraz kombinacją hash_top_keyklucza podrzędnego:

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

Celowo używamy {}notacji. Dzięki temu wszystkie te klucze wchodzą w to samo hash slot. Możesz przeczytać więcej na ten temat tutaj: https://redis.io/topics/cluster-tutorial

Teraz, jeśli chcemy wykonać tę samą operację haszowania, możemy zrobić:

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

Interesujący jest tutaj HGETALL. Najpierw otrzymujemy hash slotklucze dla wszystkich naszych dzieci. Następnie otrzymujemy klucze do tego konkretnego hash sloti ostatecznie pobieramy wartości. Musimy być tutaj ostrożni, ponieważ może być do tego coś więcej niż tylko nklucze, hash slota także mogą być klucze, które nas nie interesują, ale mają takie same hash slot. Moglibyśmy właściwie napisać Luaskrypt, który wykonałby te kroki na serwerze, wykonując polecenie EVALlub EVALSHA. Ponownie musisz wziąć pod uwagę wydajność tego podejścia w konkretnym scenariuszu.

Więcej odniesień:

hveiga
źródło
Takie podejście zużywa więcej pamięci niż proste klucze z czasem wygaśnięcia.
VasileM
3

Istnieje framework java Redisson , który implementuje Mapobiekt skrótu z obsługą TTL wejścia. Używa hmapi zsetobiektów Redis pod maską. Przykład użycia:

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

To podejście jest całkiem przydatne.

Nikita Koksharov
źródło
ale jak możesz stworzyć mapę? ponieważ nie znajduję żadnego samouczka ani metody tworzenia / ustawiania
FaNaT
@ ZoltánNémeth W Redis mapa tworzona automatycznie po wstawieniu pierwszej wartości.
Nikita Koksharov
3

Jest to możliwe w KeyDB, który jest Fork of Redis. Ponieważ jest to Fork, jest w pełni kompatybilny z Redis i działa jako kropla w zastępstwie.

Po prostu użyj polecenia EXPIREMEMBER. Działa z zestawami, skrótami i posortowanymi zestawami.

EXPIREMEMBER podklucz nazwy klucza [czas]

Możesz także użyć TTL i PTTL, aby zobaczyć datę ważności

Podklucz nazwy klucza TTL

Więcej dokumentacji można znaleźć tutaj: https://docs.keydb.dev/docs/commands/#expiremember

John Sully
źródło
2

Jeśli chodzi o implementację NodeJS, dodałem niestandardowe expiryTimepole w obiekcie, który zapisuję w HASH. Następnie po określonym czasie usuwam wygasłe wpisy HASH za pomocą następującego kodu:

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);
            }
        })
    }
});
George I. Tsopouridis
źródło
Możesz uczynić to bardziej wydajnym, używając Array.filterdo utworzenia tablicy keysdo usunięcia z skrótu, a następnie przekazania jej client.hdel(HASH_NAME, ...keys)w jednym wywołaniu.
doublesharp
const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
doublesharp
1

Możesz. Oto przykład.

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

Zastosowanie EXPIRE lub EXPIREAT poleceń.

Jeśli chcesz wygasnąć określone klucze w skrócie starsze niż 1 miesiąc. To jest niemożliwe. Polecenie Redis expire dotyczy wszystkich kluczy w skrócie. Jeśli ustawisz dzienny klucz skrótu, możesz ustawić czas życia kluczy.

hset key-20140325 f1 1
expire key-20140325 100
hset key-20140325 f1 2
Jonathan Kim
źródło
24
Myślę, że nie chce on wygasać wszystkich kluczy w skrócie, a raczej wszystkie klucze w skrócie, które są starsze niż 1 miesiąc , więc tylko niektóre z nich. Który AFAIK nie jest możliwy.
UpTheCreek
1
IMHO pytanie, załóżmy to. Więc Jonathan dostaje ode mnie +1, bo mi pomógł! Dzięki!
longliveenduro
jak tracisz ważność „f1” i „f2”?
vgoklani
4
To nie odpowiada na pytanie lub w ogóle nie pomaga. Konieczne jest wygaśnięcie elementów w skrócie, a nie samego skrótu.
Ron
@UpTheCreek Dziękuję!
Jonathan Kim,
1

Aby to osiągnąć, możesz przechowywać klucze / wartości w Redis w inny sposób, po prostu dodając przedrostek lub przestrzeń nazw do kluczy podczas ich przechowywania, np. „Hset_”

  • Uzyskaj klucz / wartość GET hset_keyrównąHGET hset key

  • Dodaj klucz / wartość SET hset_key valuerówna sięHSET hset key

  • Pobierz wszystkie klucze KEYS hset_*równa sięHGETALL hset

  • Pobieranie wszystkich wartości powinno odbywać się w 2 operacjach, najpierw pobierz wszystkie klucze, KEYS hset_*a następnie uzyskaj wartość dla każdego klucza

  • Dodaj klucz / wartość z TTL lub wygaś, co jest tematem pytania:

 SET hset_key value
 EXPIRE hset_key

Uwaga : KEYSsprawdzi dopasowanie klucza w całej bazie danych, co może mieć wpływ na wydajność, zwłaszcza jeśli masz dużą bazę danych.

Uwaga:

  • KEYSwyszuka dopasowanie klucza w całej bazie danych, co może mieć wpływ na wydajność, zwłaszcza jeśli masz dużą bazę danych. chociaż SCAN 0 MATCH hset_*może być lepszy, o ile nie blokuje serwera, ale nadal problemem jest wydajność w przypadku dużej bazy danych.

  • Możesz utworzyć nową bazę danych do oddzielnego przechowywania tych kluczy, które mają wygasnąć, zwłaszcza jeśli są to małe zestawy kluczy.

Podziękowania dla @DanFarrell, który zwrócił uwagę na problem związany z wydajnością KEYS

Muhammad Soliman
źródło
1
pamiętaj tylko, że jest to znacząca zmiana w charakterystyce wydajności
Daniel Farrell
w jaki sposób! jeśli mówimy o złożoności czasu, wszystkie te operacje mają taką samą złożoność czasową jako hashset.. get O (1) zestaw O (1) uzyskać wszystkie O (n)
Muhammad Soliman
„traktuj KEYS jako polecenie, którego należy używać w środowiskach produkcyjnych z najwyższą ostrożnością”. redis.io/commands/KEYS . HGETALL odnosi się O(n)do liczby rzeczy w zestawie, KEYSdo liczby rzeczy w DB.
Daniel Farrell,
to prawda, scan 0 match namespace:*może być lepiej, o ile nie blokuje serwera
Muhammad Soliman,
1
również oddziel te klucze, jeśli są one małe, do innej bazy danych. dzięki @DanFarrell
Muhammad Soliman,
1

Omówiliśmy tutaj ten sam problem.

Mamy hash Redis, klucz do wpisów hash (pary nazwa / wartość) i musieliśmy przechowywać indywidualne czasy wygaśnięcia dla każdego wpisu hash.

Zaimplementowaliśmy to dodając n bajtów danych prefiksowych zawierających zakodowane informacje o wygaśnięciu, kiedy piszemy wartości wejściowe skrótu, ustawiliśmy również klucz tak, aby wygasał w momencie zawartym w zapisywanej wartości.

Następnie podczas czytania dekodujemy prefiks i sprawdzamy, czy wygasł. Jest to dodatkowe obciążenie, jednak odczyty są nadal O (n), a cały klucz wygaśnie po wygaśnięciu ostatniego wpisu skrótu.

MikeZ
źródło
0

Możesz użyć powiadomień Redis Keyspace przy użyciu psubscribei "__keyevent@<DB-INDEX>__:expired".

Dzięki temu za każdym razem, gdy klucz wygaśnie, otrzymasz wiadomość opublikowaną na Twoim połączeniu redis.

Jeśli chodzi o twoje pytanie, w zasadzie tworzysz tymczasowy „normalny” klucz setz czasem wygaśnięcia w s / ms. Powinien pasować do nazwy klucza, który chcesz usunąć ze swojego zestawu.

Ponieważ twój tymczasowy klucz zostanie opublikowany w twoim połączeniu redis, które posiada, "__keyevent@0__:expired"kiedy wygasł, możesz łatwo usunąć swój klucz z oryginalnego zestawu, ponieważ wiadomość będzie miała nazwę klucza.

Prosty przykład w praktyce na tej stronie: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3

doc: https://redis.io/topics/notifications (poszukaj flagi xE)

solarissmoke
źródło
0

Możesz użyć sortowanego zestawu w redis, aby uzyskać kontener TTL z sygnaturą czasową jako wynikiem. Na przykład za każdym razem, gdy wstawisz ciąg zdarzenia do zestawu, możesz ustawić jego wynik na czas zdarzenia. W ten sposób możesz uzyskać dane z dowolnego okna czasu, dzwoniąc zrangebyscore "your set name" min-time max-time

Co więcej, możemy wygasnąć, używając zremrangebyscore "your set name" min-time max-timedo usuwania starych wydarzeń.

Jedyną wadą jest to, że musisz robić porządki z zewnętrznego procesu, aby utrzymać rozmiar zestawu.

mojians
źródło
-1

Można wygasają mieszań Redis w swobodnie, na przykład za pomocą python

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

Spowoduje to wygaśnięcie wszystkich kluczy podrzędnych w hash hashed_user po 10 sekundach

to samo z 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"

po 10 sekundach

127.0.0.1:6379> hgetall testt
(empty list or set)
Thomas John
źródło
7
pytanie dotyczy wygaśnięcia hsetdziecka nie do końca hset.
thangdc94
nie odpowiada na zadane pytanie
peteclark3