In the last article we talked about Redis’s memory flushing policy (portal), this time we will take a look at Redis’s expiration policy.

Those familiar with Redis should know that each Key of Redis can set an expiration date. When the expiration date is reached, the Key will be deleted automatically.

Precautions for setting the expiration time for a key

1.DEL/SET/GETSETSuch commands will clear the expiration time

If you run the DEL, SET, and GETSET commands to override the value corresponding to the key to operate a key with the expiration time SET, the expiration time of the key will be cleared.

// Set the expiration time of myKey to 300s 127.0.0.1:6379>set127.0.0.1:6379> TTL mykey (integer) 294 // UsesetOverwrite mykey 127.0.0.1:6379>set127.0.0.1:6379> TTL mykey (integer1) -Copy the code

2,INCR/LPUSH/HSETSuch commands do not clear the expiration time

The INCR/LPUSH/HSET command, which changes the value of a key instead of overwriting the entire value, does not clear the expiration of the key. INCR:

// Set the expiration time of incr_key to 300s 127.0.0.1:6379>setIncr_key 1 ex 300 OK 127.0.0.1:6379> TTL incr_key (integer127.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) 277
Copy the code

LPUSH:

// Add a list key with a value of 1 127.0.0.1:6379> LPUSH list 1integer) 1 // Set 300s expire time for list 127.0.0.1:6379> expire list 300 (integer1 // Query the expiration time 127.0.0.1:6379> TTL list (integer127.0.0.1:6379> lpush list 2 (127.0.0.1:6379)integer127.0.0.1:6379> lrange list 0 1 1 1)"2"
2) "1"127.0.0.1:6379> TTL list (integer) 252
Copy the code

3,PERSISTThe command clears the expiration time

When you use the PERSIST command to convert a key with an expiration date into a persistent key, the expiration time is also cleared.

127.0.0.1:6379 >setPersist_key haha ex 300 OK 127.0.0.1:6379> TTL persist_key (integer127.0.0.1:6379> persist key ()integer127.0.0.1:6379> TTL persist_key (integer1) -Copy the code

4, the use ofRENAMECommand, the expiration time of the old key will be transferred to the new key

If you run the RENAME KEY_A KEY_B command to RENAME KEY_A to KEY_B, the new key KEY_B inherits all the features of KEY_A, regardless of whether KEY_B expires or not.

// Set key_A's expiration time to 300s 127.0.0.1:6379>setKey_a value_a ex 300 OK // Set the expiration time of KEY_B to 600s 127.0.0.1:6379>setKey_b value_b ex 600 OK 127.0.0.1:6379> TTL key_a (integer) 279
127.0.0.1:6379> ttl key_b
(integer127.0.0.1:6379> rename key_A key_B OK // The new KEY_B inherits the expiration time of key_A 127.0.0.1:6379> TTL key_B (integer) 248
Copy the code

I don’t have space here, so I’m not going to list all the cases where KEY_A is renamed to KEY_B, but you can try it out on your computer when key_A is set to expire and KEY_B is not set to expire.

5, useEXPIRE/PEXPIRESet the expiration time to negative or useEXPIREAT/PEXPIREATSetting the expiration timestamp to a past time will cause the key to be deleted

The EXPIRE.

127.0.0.1:6379 >setKey_1 value_1 OK 127.0.0.1:6379> get key_1"value_1"// Set expiration time to -1 127.0.0.1:6379> EXPIRE key_1 -1 (integer127.0.0.1:6379> get key_1 (nil)Copy the code

EXPIREAT:

127.0.0.1:6379 >setKey_2 value_2 OK 127.0.0.1:6379> get key_2"value_2"// Set the timestamp to past time 127.0.0.1:6379> expireat key_2 10000 (integer127.0.0.1:6379> get key_2 (nil)Copy the code

6,EXPIRECommand to update the expiration time

With the EXPIRE command, you can update a key that already has an expiration date.

// Set key_1 expiration time to 100s 127.0.0.1:6379>setKey_1 value_1 ex 100 OK 127.0.0.1:6379> TTL key_1 (integer127.0.0.1:6379> Expire KEY_1 300 (integer) 1
127.0.0.1:6379> ttl key_1
(integer) 295
Copy the code

In versions below Redis2.1.3, updating the expire time of a key that has been set will fail using the expire command. In addition, Redis will delete a key whose value is changed by LPUSH/HSET.

Redis expiration policy

If there are a large number of keys in Redis, how can we efficiently find out expired keys and delete them? Do you have to go through every key? If a large number of keys expire at the same time, will Redis process expiration events all the time, causing read/write instructions to lag?

As a caveat, Redis is single-threaded, so some time-consuming operations can cause Redis to stall, such as listing all keys using the keys * command when the Redis data volume is particularly high.

Redis actually uses a combination of lazy deletion and periodic deletion to deal with expired keys.

Lazy to delete

Lazy deletion means that when the client accesses the key, Redis checks the expiration time of the key and deletes the key immediately if it expires.

This seems like a perfect way to check the expiration of a key at access time without consuming too much additional CPU resources. But if a key is out of date, if it has not been accessed for a long time, the key will remain in memory forever, severely consuming memory resources.

Periodically delete

The principle of periodic deletion is that Redis will put all keys with expiration dates into a dictionary, and then every once in a while a random number of keys from the dictionary will check expiration dates and delete expired keys.

Redis defaults to 10 expiration scans per second:

  1. Random 20 keys from the expired dictionary

  2. Delete expired keys among the 20 keys

  3. If more than 25% of the keys are expired, repeat the first step

At the same time, Redis also sets the upper limit of scanning time, which is not more than 25ms by default.

The resources

Redis. IO/commands/ex…