Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "EXPIRE" the "HSET" child key in redis?

Tags:

redis

hash

This is not possible, for the sake of keeping Redis simple.

Quoth Antirez, creator of Redis:

Hi, it is not possible, either use a different top-level key for that specific field, or store along with the filed another field with an expire time, fetch both, and let the application understand if it is still valid or not based on current time.


Redis does not support having TTL on hashes other than the top key, which would expire the whole hash. If you are using a sharded cluster, there is another approach you could use. This approach could not be useful in all scenarios and the performance characteristics might differ from the expected ones. Still worth mentioning:

When having a hash, the structure basically looks like:

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

Since we want to add TTL to the child keys, we can move them to top keys. The main point is that the key now should be a combination of hash_top_key and child key:

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

We are using the {} notation on purpose. This allows all those keys to fall in the same hash slot. You can read more about it here: https://redis.io/topics/cluster-tutorial

Now if we want to do the same operation of hashes, we could do:

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

The interesting one here is HGETALL. First we get the hash slot for all our children keys. Then we get the keys for that particular hash slot and finally we retrieve the values. We need to be careful here since there could be more than n keys for that hash slot and also there could be keys that we are not interested in but they have the same hash slot. We could actually write a Lua script to do those steps in the server by executing an EVAL or EVALSHA command. Again, you need to take into consideration the performance of this approach for your particular scenario.

Some more references:

  • https://redis.io/commands/cluster-keyslot
  • https://redis.io/commands/cluster-getkeysinslot
  • https://redis.io/commands/eval

This is possible in KeyDB which is a Fork of Redis. Because it's a Fork its fully compatible with Redis and works as a drop in replacement.

Just use the EXPIREMEMBER command. It works with sets, hashes, and sorted sets.

EXPIREMEMBER keyname subkey [time]

You can also use TTL and PTTL to see the expiration

TTL keyname subkey

More documentation is available here: https://docs.keydb.dev/docs/commands/#expiremember


You can use Sorted Set in redis to get a TTL container with timestamp as score. For example, whenever you insert a event string into the set you can set its score to the event time. Thus you can get data of any time window by calling zrangebyscore "your set name" min-time max-time

Moreover, we can do expire by using zremrangebyscore "your set name" min-time max-time to remove old events.

The only drawback here is you have to do housekeeping from an outsider process to maintain the size of the set.