¿Cómo "EXPIRAR" la clave secundaria "HSET" en redis?

107

Necesito caducar todas las claves en redis hash, que tienen más de 1 mes.

aieven
fuente

Respuestas:

117

Esto no es posible , en aras de mantener Redis simple .

Quoth Antirez, creador de Redis:

Hola, no es posible, use una clave de nivel superior diferente para ese campo específico, o almacene junto con el archivo archivado otro campo con un tiempo de vencimiento, obtenga ambos y deje que la aplicación comprenda si aún es válida o no según tiempo actual.

Supr
fuente
8
esta es la razón por la que redis es un software tan impresionante. ellos saben dónde mantenerlo simple
hasta el
20

Redis no admite tener TTLhash que no sean la clave superior, que expiraría todo el hash. Si está utilizando un clúster fragmentado, existe otro enfoque que podría utilizar. Este enfoque podría no ser útil en todos los escenarios y las características de desempeño podrían diferir de las esperadas. Todavía vale la pena mencionar:

Al tener un hash, la estructura básicamente se ve así:

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

Como queremos agregar TTLa las claves secundarias, podemos moverlas a las claves superiores. El punto principal es que la clave ahora debería ser una combinación de una hash_top_keyclave secundaria:

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

Estamos usando la {}notación a propósito. Esto permite que todas esas llaves caigan en la misma hash slot. Puede leer más sobre esto aquí: https://redis.io/topics/cluster-tutorial

Ahora bien, si queremos hacer la misma operación de hashes, podríamos hacer:

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

El interesante aquí es HGETALL. Primero obtenemos las hash slotclaves para todos nuestros hijos. Luego obtenemos las claves para ese particular hash sloty finalmente recuperamos los valores. Debemos tener cuidado aquí, ya que podría haber más que nclaves para eso hash sloty también podría haber claves que no nos interesan pero tienen las mismas hash slot. De hecho, podríamos escribir un Luascript para realizar esos pasos en el servidor ejecutando un comando EVALo EVALSHA. Nuevamente, debe tener en cuenta el rendimiento de este enfoque para su escenario particular.

Algunas referencias más:

hveiga
fuente
Este enfoque usa más memoria que las claves simples con tiempo de caducidad.
VasileM
3

Existe un marco Java de Redisson que implementa un Mapobjeto hash con soporte TTL de entrada. Utiliza hmapy zsetRedis objetos debajo del capó. Ejemplo de uso:

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

Este enfoque es bastante útil.

Nikita Koksharov
fuente
pero ¿cómo se puede crear un mapa? porque no encuentro ningún tutorial o un método de creación / configuración
FaNaT
@ ZoltánNémeth In Redis mapa creado automáticamente cuando se inserta el primer valor.
Nikita Koksharov
3

Esto es posible en KeyDB, que es una bifurcación de Redis. Debido a que es un Fork, es totalmente compatible con Redis y funciona como un reemplazo directo.

Simplemente use el comando EXPIREMEMBER. Funciona con conjuntos, hashes y conjuntos ordenados.

EXPIREMEMBER subclave de nombre clave [hora]

También puede usar TTL y PTTL para ver el vencimiento

Subclave de nombre de clave TTL

Más documentación está disponible aquí: https://docs.keydb.dev/docs/commands/#expiremember

John Sully
fuente
2

Con respecto a la implementación de NodeJS, agregué un expiryTimecampo personalizado en el objeto que guardo en el HASH. Luego, después de un período de tiempo específico, borro las entradas HASH caducadas usando el siguiente código:

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
fuente
Puede hacer que esto sea más eficiente utilizando Array.filterpara crear una matriz de keyspara eliminar del hash y luego pasar eso client.hdel(HASH_NAME, ...keys)en una sola llamada.
doublesharp
const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
doublesharp
1

Usted puede. Aquí hay un ejemplo.

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

Uso EXPIRE o EXPIREAT comando.

Si desea caducar claves específicas en el hash de más de 1 mes. Esto no es posible. El comando Redis expire es para todas las claves en el hash. Si establece una clave hash diaria, puede establecer un tiempo de vida de las claves.

hset key-20140325 f1 1
expire key-20140325 100
hset key-20140325 f1 2
Jonathan Kim
fuente
24
No creo que quiera caducar todas las claves en el hash, más bien todas las claves en el hash que tienen más de 1 mes , así que solo algunas de ellas. Lo que AFAIK no es posible.
UpTheCreek
1
En mi humilde opinión, la pregunta supongamos esto. ¡Entonces Jonathan obtiene +1 de mí, porque me ayudó! ¡Gracias!
longliveenduro
¿Cómo expira "f1" y "f2"?
vgoklani
4
Esto no responde a la pregunta ni ayuda en absoluto. La necesidad es caducar los elementos del hash, no el hash en sí.
Ron
@UpTheCreek ¡Gracias!
Jonathan Kim
1

Puede almacenar claves / valores en Redis de manera diferente para lograr esto, simplemente agregando un prefijo o espacio de nombres a sus claves cuando las almacena, por ejemplo, "hset_"

  • Obtener una clave / valor GET hset_keyigual aHGET hset key

  • Agregar una clave / valor SET hset_key valueigual aHSET hset key

  • Obtener todas las claves KEYS hset_*iguales aHGETALL hset

  • Obtener todos los valores debe hacerse en 2 operaciones, primero obtenga todas las claves y KEYS hset_*luego obtenga el valor para cada clave

  • Agregue una clave / valor con TTL o expire, que es el tema de la pregunta:

 SET hset_key value
 EXPIRE hset_key

Nota : KEYSbuscará coincidir con la clave en toda la base de datos, lo que puede afectar el rendimiento, especialmente si tiene una gran base de datos.

Nota:

  • KEYSbuscará coincidir con la clave en toda la base de datos, lo que puede afectar el rendimiento, especialmente si tiene una gran base de datos. aunque SCAN 0 MATCH hset_*podría ser mejor siempre que no bloquee el servidor, pero el rendimiento sigue siendo un problema en el caso de una gran base de datos.

  • Puede crear una nueva base de datos para almacenar por separado estas claves que desea que caduquen, especialmente si son un pequeño conjunto de claves.

Gracias a @DanFarrell, quien destacó el problema de rendimiento relacionado con KEYS

Muhammad Soliman
fuente
1
solo tenga en cuenta que este es un cambio significativo en las características de rendimiento
Daniel Farrell
¡cómo! si habla de complejidades temporales, todas estas operaciones tienen la misma complejidad temporal que hashset... obtener O (1) establecer O (1) obtener todas O (n)
Muhammad Soliman
"Considere KEYS como un comando que solo debe usarse en entornos de producción con sumo cuidado". redis.io/commands/KEYS . HGETALL es O(n)para varias cosas en el conjunto, KEYSpara varias cosas en la base de datos.
Daniel Farrell
eso es cierto, scan 0 match namespace:*podría ser mejor siempre y cuando no bloquee el servidor
Muhammad Soliman
1
Además, separe estas claves, si son un conjunto pequeño, en una base de datos diferente. gracias @DanFarrell
Muhammad Soliman
1

Tuvimos el mismo problema discutido aquí.

Tenemos un hash de Redis, una clave para las entradas de hash (pares de nombre / valor), y necesitábamos mantener tiempos de vencimiento individuales en cada entrada de hash.

Implementamos esto agregando n bytes de datos de prefijo que contienen información de caducidad codificada cuando escribimos los valores de entrada de hash, también configuramos la clave para que caduque en el momento contenido en el valor que se escribe.

Luego, al leer, decodificamos el prefijo y verificamos su vencimiento. Esto es una sobrecarga adicional, sin embargo, las lecturas siguen siendo O (n) y la clave completa caducará cuando haya caducado la última entrada hash.

MikeZ
fuente
0

Puede usar las notificaciones del espacio de claves de Redis usando psubscribey "__keyevent@<DB-INDEX>__:expired".

Con eso, cada vez que caduque una clave, recibirá un mensaje publicado en su conexión redis.

Con respecto a su pregunta, básicamente, crea una clave "normal" temporal setcon un tiempo de vencimiento en s / ms. Debe coincidir con el nombre de la clave que desea eliminar en su conjunto.

Como su clave temporal se publicará en su conexión de redis manteniendo el "__keyevent@0__:expired"cuando expire, puede eliminar fácilmente su clave de su conjunto original ya que el mensaje tendrá el nombre de la clave.

Un ejemplo sencillo en la práctica en esa página: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3

doc: https://redis.io/topics/notifications (busque la bandera xE)

humo solar
fuente
0

Puede utilizar Sorted Set en redis para obtener un contenedor TTL con marca de tiempo como puntuación. Por ejemplo, cada vez que inserta una cadena de evento en el conjunto, puede establecer su puntuación en la hora del evento. Por lo tanto, puede obtener datos de cualquier ventana de tiempo llamando zrangebyscore "your set name" min-time max-time

Además, podemos caducar utilizando zremrangebyscore "your set name" min-time max-timepara eliminar eventos antiguos.

El único inconveniente aquí es que tienes que hacer la limpieza desde un proceso externo para mantener el tamaño del conjunto.

mojianos
fuente
-1

Puede caducar los hash de Redis con facilidad, por ejemplo, usando python

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

Esto expirará todas las claves secundarias en hash hashed_user después de 10 segundos

lo mismo 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"

después de 10 segundos

127.0.0.1:6379> hgetall testt
(empty list or set)
Thomas John
fuente
6
La pregunta es sobre el hsetniño expira, no el completo hset.
thangdc94
no responde la pregunta formulada
peteclark3