作者:千山qianshan
juejin.im/post/5d6bda096fb9a06acc009dc8

相熟Redis的同学应该晓得,Redis的每个Key都能够设置一个过期工夫,当达到过期工夫的时候,这个key就会被主动删除。

在为key设置过期工夫须要留神的事项

1、 DEL/SET/GETSET等命令会革除过期工夫

在应用DEL、SET、GETSET等会笼罩key对应value的命令操作一个设置了过期工夫的key的时候,会导致对应的key的过期工夫被革除。

//设置mykey的过期工夫为300s127.0.0.1:6379> set mykey hello ex 300OK//查看过期工夫127.0.0.1:6379> ttl mykey(integer) 294//应用set命令笼罩mykey的内容127.0.0.1:6379> set mykey ollehOK//过期工夫被革除127.0.0.1:6379> ttl mykey(integer) -1

2、INCR/LPUSH/HSET等命令则不会革除过期工夫

而在应用INCR/LPUSH/HSET这种只是批改一个key的value,而不是笼罩整个value的命令,则不会革除key的过期工夫。

INCR:

//设置incr_key的过期工夫为300s  127.0.0.1:6379> set incr_key 1 ex 300  OK  127.0.0.1:6379> ttl incr_key  (integer) 291  //进行自增操作  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) 277

LPUSH:

//新增一个list类型的key,并增加一个为1的值  127.0.0.1:6379> LPUSH list 1  (integer) 1  //为list设置300s的过期工夫  127.0.0.1:6379> expire list 300  (integer) 1  //查看过期工夫  127.0.0.1:6379> ttl list  (integer) 292  //往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) 252

3、PERSIST命令会革除过期工夫

当应用PERSIST命令将一个设置了过期工夫的key转变成一个长久化的key的时候,也会革除过期工夫。

127.0.0.1:6379> set persist_key haha ex 300  OK  127.0.0.1:6379> ttl persist_key  (integer) 296  //将key变为长久化的  127.0.0.1:6379> persist persist_key  (integer) 1  //过期工夫被革除  127.0.0.1:6379> ttl persist_key  (integer) -1

4、应用RENAME命令,老key的过期工夫将会转到新key上

在应用例如:RENAME KEY_A KEY_B命令将KEY_A重命名为KEY_B,不论KEY_B有没有设置过期工夫,新的key KEY_B将会继承KEY_A的所有个性。

//设置key_a的过期工夫为300s127.0.0.1:6379> set key_a value_a ex 300OK//设置key_b的过期工夫为600s127.0.0.1:6379> set key_b value_b ex 600OK127.0.0.1:6379> ttl key_a(integer) 279127.0.0.1:6379> ttl key_b(integer) 591//将key_a重命名为key_b127.0.0.1:6379> rename key_a key_bOK//新的key_b继承了key_a的过期工夫127.0.0.1:6379> ttl key_b(integer) 248

这里篇幅无限,我就不一一将key_a重命名到key_b的各个状况列出来,大家能够在本人电脑上试一下key_a设置了过期工夫,key_b没设置过期工夫这种状况。

5、应用EXPIRE/PEXPIRE设置的过期工夫为正数或者应用EXPIREAT/PEXPIREAT设置过期工夫戳为过来的工夫会导致key被删除

EXPIRE:

127.0.0.1:6379> set key_1 value_1OK127.0.0.1:6379> get key_1"value_1"//设置过期工夫为-1127.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_2OK127.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命令能够更新过期工夫

对一个曾经设置了过期工夫的key应用expire命令,能够更新其过期工夫。

//设置key_1的过期工夫为100s127.0.0.1:6379> set key_1 value_1 ex 100OK127.0.0.1:6379> ttl key_1(integer) 95更新key_1的过期工夫为300s127.0.0.1:6379> expire key_1 300(integer) 1127.0.0.1:6379> ttl key_1(integer) 295

在Redis2.1.3以下的版本中,应用expire命令更新一个曾经设置了过期工夫的key的过期工夫会失败。并且对一个设置了过期工夫的key应用LPUSH/HSET等命令批改其value的时候,会导致Redis删除该key。

Redis的过期策略

那你有没有想过一个问题,Redis外面如果有大量的key,怎样才能高效的找出过期的key并将其删除呢,难道是遍历每一个key吗?如果同一期间过期的key十分多,Redis会不会因为始终解决过期事件,而导致读写指令的卡顿。

这里阐明一下,Redis是单线程的,所以一些耗时的操作会导致Redis卡顿,比方当Redis数据量特地大的时候,应用keys * 命令列出所有的key。

实际上Redis应用懈怠删除+定期删除相结合的形式解决过期的key。

懈怠删除

所谓懈怠删除就是在客户端拜访该key的时候,redis会对key的过期工夫进行查看,如果过期了就立刻删除。

这种形式看似很完满,在拜访的时候查看key的过期工夫,不会占用太多的额定CPU资源。然而如果一个key曾经过期了,如果长时间没有被拜访,那么这个key就会始终存留在内存之中,重大耗费了内存资源。

定期删除

定期删除的原理是,Redis会将所有设置了过期工夫的key放入一个字典中,而后每隔一段时间从字典中随机一些key查看过期工夫并删除已过期的key。

Redis默认每秒进行10次过期扫描:

  1. 从过期字典中随机20个key
  2. 删除这20个key中已过期的
  3. 如果超过25%的key过期,则反复第一步

同时,为了保障不呈现循环适度的状况,Redis还设置了扫描的工夫下限,默认不会超过25ms。