Redis setting expiration time considerations

Preface

Those who have used Redis should know that each key of Redis can set an expiration time. When the expiration time is reached, the key will be automatically deleted. But sometimes we will find that some keys with an expiration time have not expired at the time we set. Here we will talk about the expiration time in detail.

Things to pay attention to when setting expiration time

1. Commands such as DEL/SET/GETSET will clear the expiration time

When using commands such as DEL, SET, GETSET, etc. that will overwrite the value corresponding to the key to operate a key with an expiration time set, the expiration time of the corresponding key will be cleared.

//设置mykey的过期时间为500s
127.0.0.1:6379> set tkey test ex 500
OK
//查看过期时间
127.0.0.1:6379> ttl tkey 
(integer) 294
//使用set命令覆盖tkey的内容
127.0.0.1:6379> set tkey updatetest
OK
//过期时间被清除
127.0.0.1:6379> ttl tkey
(integer) -1

2. Commands such as INCR/LPUSH/HSET will not clear the expiration time

When using INCR/LPUSH/HSET commands that only modify the value of a key instead of overwriting the entire value, the key expiration time will not be cleared.

INCR:

//设置incr_key的过期时间为500s
127.0.0.1:6379> set incr_key 1 ex 500
OK
127.0.0.1:6379> ttl incr_key
(integer) 390
//进行自增操作
127.0.0.1:6379> incr incr_key
(integer) 2
127.0.0.1:6379> get incr_key
"2"
//查询过期时间,发现过期时间没有被清除
127.0.0.1:6379> ttl incr_key
(integer) 312

LPUSH:

//新增一个list类型的key,并添加一个为1的值
127.0.0.1:6379> LPUSH list 1
(integer) 1
//为list设置500s的过期时间
127.0.0.1:6379> expire list 500
(integer) 1
//查看过期时间
127.0.0.1:6379> ttl list
(integer) 392
//往list里面添加值2
127.0.0.1:6379> lpush list 2
(integer) 2
//查看list的所有值
127.0.0.1:6379> lrange list 0 1
1) "2"
2) "1"
//能看到往list里面添加值并没有使过期时间清除
127.0.0.1:6379> ttl list
(integer) 352

3. The PERSIST command will clear the expiration time

When using the PERSIST command to convert a key with an expiration time set to a persistent key, the expiration time will also be cleared.

127.0.0.1:6379> set persist_key hello ex 400
OK
127.0.0.1:6379> ttl persist_key
(integer) 396
//将key变为持久化的
127.0.0.1:6379> persist persist_key
(integer) 1
//过期时间被清除
127.0.0.1:6379> ttl persist_key
(integer) -1

4. Using the RENAME command, the expiration time of the old key will be transferred to the new key

For example, use the RENAME KEY_1 KEY_2 command to rename KEY_1 to KEY_2. Regardless of whether KEY_1 has an expiration time set, the new key KEY_2 will inherit all the characteristics of KEY_1.

//设置key_1的过期时间为400s
127.0.0.1:6379> set key_1 value_1 ex 400
OK
//设置key_2的过期时间为500s
127.0.0.1:6379> set key_2 value_2 ex 500
OK
127.0.0.1:6379> ttl key_1
(integer) 379
127.0.0.1:6379> ttl key_2
(integer) 391
//将key_1重命名为key_2
127.0.0.1:6379> rename key_1 key_2
OK
//新的key_1继承了key_2的过期时间
127.0.0.1:6379> ttl key_2
(integer) 348

5. Use EXPIRE/PEXPIRE to set the expiration time to be a negative number or use EXPIREAT/PEXPIREAT to set the expiration time stamp to a time in the past, which will cause the key to be deleted

EXPIRE:

127.0.0.1:6379> set key_1 value_1
OK
127.0.0.1:6379> get key_1
"value_1"
//设置过期时间为-1
127.0.0.1:6379> expire key_1 -1
(integer) 1
//发现key被删除
127.0.0.1:6379> get key_1
(nil)

EXPIREAT:

127.0.0.1:6379> set key_2 value_2
OK
127.0.0.1:6379> get key_2
"value_2"
//设置的时间戳为过去的时间
127.0.0.1:6379> expireat key_2 10000
(integer) 1
//key被删除
127.0.0.1:6379> get key_2
(nil)

6. EXPIRE command can update the expiration time

Use the expire command on a key that has an expiration time set to update its expiration time.

//设置key_1的过期时间为100s
127.0.0.1:6379> set key_1 value_1 ex 100
OK
127.0.0.1:6379> ttl key_1
(integer) 95
//更新key_1的过期时间为300s
127.0.0.1:6379> expire key_1 300
(integer) 1
127.0.0.1:6379> ttl key_1
(integer) 295

In versions below Redis 2.1.3, using the expire command to update the expiration time of a key with an expiration time set will fail. And when using LPUSH/HSET and other commands to modify the value of a key with an expiration time set, it will cause Redis to delete the key.

Redis expiration strategy

If there are a large number of keys in Redis, how can we efficiently find out the expired keys and delete them? If the traversal method is adopted, if there are a lot of expired keys in the same period, will Redis always deal with expired events? Stuttering of read and write instructions.

Because Redis is single-threaded, some time-consuming operations will cause Redis to freeze. For example, when the amount of Redis data is very large, use the keys * command to list all keys.

In fact, Redis uses a combination of lazy deletion + periodic deletion to deal with expired keys.

1. Lazy delete

Lazy deletion means that when the client accesses the key, redis will check the expiration time of the key and delete it immediately if it expires.

This method seems perfect. Checking the expiration time of the key during access will not take up too much additional CPU resources. But if a key has expired, if it has not been accessed for a long time, then the key will always be stored in the memory, seriously consuming memory resources.

2. Delete regularly

The principle of regular deletion is that Redis will put all keys with an expiration time set into a dictionary, and then randomly some keys from the dictionary will check the expiration time and delete the expired keys at regular intervals.

Redis performs 10 expired scans per second by default:

(1) Randomly 20 keys from the expired dictionary
(2) Delete the expired keys among these 20 keys
(3) If more than 25% of the keys expire, repeat the first step

At the same time, in order to ensure that there is no excessive looping, Redis also sets the upper limit of scanning time, which will not exceed 25ms by default.

Guess you like

Origin blog.csdn.net/cyb_123/article/details/107799058