How to “EXPIRE” the “HSET” child key in redis?

前端 未结 11 1969
予麋鹿
予麋鹿 2020-11-30 21:10

I need to expire all keys in redis hash, which are older than 1 month.

相关标签:
11条回答
  • 2020-11-30 21:22

    Regarding a NodeJS implementation, I have added a custom expiryTime field in the object I save in the HASH. Then after a specific period time, I clear the expired HASH entries by using the following 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);
                }
            })
        }
    });
    
    0 讨论(0)
  • 2020-11-30 21:23

    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
    0 讨论(0)
  • 2020-11-30 21:23

    There is a Redisson java framework which implements hash Map object with entry TTL support. It uses hmap and zset Redis objects under the hood. Usage example:

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

    This approach is quite useful.

    0 讨论(0)
  • 2020-11-30 21:24

    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

    0 讨论(0)
  • 2020-11-30 21:25

    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.

    0 讨论(0)
  • 2020-11-30 21:29

    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.

    0 讨论(0)
提交回复
热议问题