Respostas:
Isso não é possível , para manter o Redis simples .
Quoth Antirez, criador do Redis:
Olá, não é possível, usar uma chave de nível superior diferente para aquele campo específico ou armazenar junto com o campo outro campo com um tempo de expiração, buscar ambos e deixar que o aplicativo entenda se ainda é válido ou não com base em hora atual.
O Redis não oferece suporte TTL
para hashes diferentes da chave superior, que expiraria todo o hash. Se você estiver usando um cluster fragmentado, há outra abordagem que você pode usar. Essa abordagem pode não ser útil em todos os cenários e as características de desempenho podem ser diferentes das esperadas. Ainda vale a pena mencionar:
Ao ter um hash, a estrutura basicamente se parece com:
hash_top_key
- child_key_1 -> some_value
- child_key_2 -> some_value
...
- child_key_n -> some_value
Visto que queremos adicionar TTL
as chaves filhas, podemos movê-las para as chaves superiores. O ponto principal é que a chave agora deve ser uma combinação de uma hash_top_key
chave filha:
{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 a {}
notação de propósito. Isso permite que todas as chaves caiam na mesma hash slot
. Você pode ler mais sobre isso aqui: https://redis.io/topics/cluster-tutorial
Agora, se quisermos fazer a mesma operação de hashes, poderíamos fazer:
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
O interessante aqui é HGETALL
. Primeiro, obtemos as hash slot
chaves para todos os nossos filhos. Em seguida, obtemos as chaves para aquele particular hash slot
e, finalmente, recuperamos os valores. Precisamos ter cuidado aqui, pois pode haver mais do que n
chaves para isso hash slot
e também pode haver chaves nas quais não estamos interessados, mas que têm as mesmas hash slot
. Na verdade, poderíamos escrever um Lua
script para fazer essas etapas no servidor executando um comando EVAL
ou EVALSHA
. Novamente, você precisa levar em consideração o desempenho dessa abordagem para seu cenário específico.
Mais algumas referências:
Existe um framework Java Redisson que implementa Map
objeto hash com suporte TTL de entrada. Ele usa hmap
e zset
objetos Redis sob o capô. Exemplo de uso:
RMapCache<Integer, String> map = redisson.getMapCache('map');
map.put(1, 30, TimeUnit.DAYS); // this entry expires in 30 days
Essa abordagem é bastante útil.
Isso é possível no KeyDB, que é um fork do Redis. Por ser um Fork, é totalmente compatível com o Redis e funciona como um substituto.
Basta usar o comando EXPIREMEMBER. Funciona com conjuntos, hashes e conjuntos classificados.
EXPIREMEMBER subchave de nome-chave [hora]
Você também pode usar TTL e PTTL para ver a validade
Subchave TTL keyname
Mais documentação está disponível aqui: https://docs.keydb.dev/docs/commands/#expiremember
Em relação a uma implementação de NodeJS, adicionei um expiryTime
campo personalizado no objeto que salvo no HASH. Então, após um período específico, eu limpo as entradas HASH expiradas usando o seguinte 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);
}
})
}
});
Array.filter
para criar uma matriz de keys
para excluir do hash e, em seguida, passar para client.hdel(HASH_NAME, ...keys)
em uma única chamada.
const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
Você pode. Aqui está um exemplo.
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
Use EXPIRE ou EXPIREAT comando.
Se você deseja expirar chaves específicas no hash com mais de 1 mês. Isso não é possível. O comando de expiração do Redis é para todas as chaves no hash. Se você definir a chave hash diária, poderá definir uma hora de vida das chaves.
hset key-20140325 f1 1
expire key-20140325 100
hset key-20140325 f1 2
Você poderia armazenar chaves / valores no Redis de maneira diferente para conseguir isso, apenas adicionando um prefixo ou namespace às suas chaves ao armazená-las, por exemplo, "hset_"
Obtenha uma chave / valor GET hset_key
igual aHGET hset key
Adicionar uma chave / valor SET hset_key value
igual aHSET hset key
Pegue todas as chaves KEYS hset_*
iguais aHGETALL hset
Obter todos os vals deve ser feito em 2 operações, primeiro pegue todas as chaves e, em KEYS hset_*
seguida, obtenha o valor de cada chave
Adicione uma chave / valor com TTL ou expire, o que é o tópico da questão:
SET hset_key value
EXPIRE hset_key
Nota : KEYS
irá pesquisar a correspondência da chave em todo o banco de dados, o que pode afetar o desempenho, especialmente se você tiver um banco de dados grande.
Nota:
KEYS
irá pesquisar a correspondência da chave em todo o banco de dados, o que pode afetar o desempenho, especialmente se você tiver um banco de dados grande. enquantoSCAN 0 MATCH hset_*
pode ser melhor, desde que não bloqueie o servidor, mas ainda assim o desempenho é um problema no caso de banco de dados grande.
Você pode criar um novo banco de dados para armazenar separadamente essas chaves que deseja expirar, especialmente se forem um pequeno conjunto de chaves.
Agradecimentos a @DanFarrell que destacou o problema de desempenho relacionado a
KEYS
hashset
.. get O (1) set O (1) get all O (n)
O(n)
para número de coisas no conjunto, KEYS
para número de coisas no banco de dados.
scan 0 match namespace:*
pode ser melhor, desde que não bloqueie o servidor
Tivemos o mesmo problema discutido aqui.
Temos um hash Redis, uma chave para entradas de hash (pares nome / valor) e precisamos manter os tempos de expiração individuais em cada entrada de hash.
Implementamos isso adicionando n bytes de dados de prefixo contendo informações de expiração codificadas quando gravamos os valores de entrada de hash, também definimos a chave para expirar no momento contido no valor sendo escrito.
Então, na leitura, decodificamos o prefixo e verificamos a validade. Esta é uma sobrecarga adicional, entretanto, as leituras ainda são O (n) e a chave inteira expirará quando a última entrada hash expirar.
Você pode usar as notificações do Redis Keyspace usando psubscribe
e "__keyevent@<DB-INDEX>__:expired"
.
Com isso, cada vez que uma chave expirar, você receberá uma mensagem publicada em sua conexão do redis.
Em relação à sua pergunta basicamente você cria uma chave "normal" temporária set
com um tempo de expiração em s / ms. Deve corresponder ao nome da chave que você deseja excluir do seu conjunto.
Como sua chave temporária será publicada na conexão do redis com o "__keyevent@0__:expired"
quando expirar, você pode excluir facilmente sua chave do conjunto original, pois a mensagem terá o nome da chave.
Um exemplo simples na prática nessa página: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3
doc: https://redis.io/topics/notifications (procure o sinalizador xE)
Você pode usar Sorted Set no redis para obter um contêiner TTL com carimbo de data / hora como pontuação. Por exemplo, sempre que você inserir uma string de evento no conjunto, poderá definir sua pontuação para a hora do evento. Assim, você pode obter dados de qualquer janela de tempo chamando
zrangebyscore "your set name" min-time max-time
Além disso, podemos expirar usando zremrangebyscore "your set name" min-time max-time
para remover eventos antigos.
A única desvantagem aqui é que você precisa fazer a manutenção de um processo externo para manter o tamanho do conjunto.
Você pode expirar hashes Redis facilmente, por exemplo, usando python
import redis
conn = redis.Redis('localhost')
conn.hmset("hashed_user", {'name': 'robert', 'age': 32})
conn.expire("hashed_user", 10)
Isso irá expirar todas as chaves filhas em hash hashed_user após 10 segundos
o mesmo 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"
após 10 segundos
127.0.0.1:6379> hgetall testt
(empty list or set)
hset
filho não o completo hset
.