服务器之家:专注于服务器技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - 在Redis中设置了过期时间的Key,需要注意哪些问题?

在Redis中设置了过期时间的Key,需要注意哪些问题?

2020-06-11 22:57Java知音佚名 Redis

熟悉Redis的同学应该知道,Redis的每个Key都可以设置一个过期时间,当达到过期时间的时候,这个key就会被自动删除。

在Redis中设置了过期时间的Key,需要注意哪些问题?

熟悉Redis的同学应该知道,Redis的每个Key都可以设置一个过期时间,当达到过期时间的时候,这个key就会被自动删除。

在为key设置过期时间需要注意的事项

1、 DEL/SET/GETSET等命令会清除过期时间

在使用DEL、SET、GETSET等会覆盖key对应value的命令操作一个设置了过期时间的key的时候,会导致对应的key的过期时间被清除。

  1. //设置mykey的过期时间为300s  
  2. 127.0.0.1:6379> set mykey hello ex 300  
  3. OK  
  4. //查看过期时间  
  5. 127.0.0.1:6379> ttl mykey  
  6. (integer) 294  
  7. //使用set命令覆盖mykey的内容  
  8. 127.0.0.1:6379> set mykey olleh  
  9. OK  
  10. //过期时间被清除  
  11. 127.0.0.1:6379> ttl mykey  
  12. (integer) -1  

2、INCR/LPUSH/HSET等命令则不会清除过期时间

而在使用INCR/LPUSH/HSET这种只是修改一个key的value,而不是覆盖整个value的命令,则不会清除key的过期时间。

INCR:

  1. //设置incr_key的过期时间为300s  
  2. 127.0.0.1:6379> set incr_key 1 ex 300  
  3. OK  
  4. 127.0.0.1:6379> ttl incr_key  
  5. (integer) 291  
  6. //进行自增操作  
  7. 127.0.0.1:6379> incr incr_key  
  8. (integer) 2  
  9. 127.0.0.1:6379> get incr_key  
  10. "2"  
  11. //查询过期时间,发现过期时间没有被清除  
  12. 127.0.0.1:6379> ttl incr_key  
  13. (integer) 277  

LPUSH:

  1. //新增一个list类型的key,并添加一个为1的值  
  2. 127.0.0.1:6379> LPUSH list 1  
  3. (integer) 1  
  4. //为list设置300s的过期时间  
  5. 127.0.0.1:6379> expire list 300  
  6. (integer) 1  
  7. //查看过期时间  
  8. 127.0.0.1:6379> ttl list  
  9. (integer) 292  
  10. //往list里面添加值2  
  11. 127.0.0.1:6379> lpush list 2  
  12. (integer) 2  
  13. //查看list的所有值  
  14. 127.0.0.1:6379> lrange list 0 1  
  15. 1) "2"  
  16. 2) "1"  
  17. //能看到往list里面添加值并没有使过期时间清除  
  18. 127.0.0.1:6379> ttl list  
  19. (integer) 252  

3、PERSIST命令会清除过期时间

当使用PERSIST命令将一个设置了过期时间的key转变成一个持久化的key的时候,也会清除过期时间。

  1. 127.0.0.1:6379> set persist_key haha ex 300  
  2. OK  
  3. 127.0.0.1:6379> ttl persist_key  
  4. (integer) 296  
  5. //将key变为持久化的  
  6. 127.0.0.1:6379> persist persist_key  
  7. (integer) 1  
  8. //过期时间被清除  
  9. 127.0.0.1:6379> ttl persist_key  
  10. (integer) -1  

4、使用RENAME命令,老key的过期时间将会转到新key上

在使用例如:RENAME KEY_A KEY_B命令将KEY_A重命名为KEY_B,不管KEY_B有没有设置过期时间,新的key KEY_B将会继承KEY_A的所有特性。

  1. //设置key_a的过期时间为300s  
  2. 127.0.0.1:6379> set key_a value_a ex 300  
  3. OK  
  4. //设置key_b的过期时间为600s  
  5. 127.0.0.1:6379> set key_b value_b ex 600  
  6. OK  
  7. 127.0.0.1:6379> ttl key_a  
  8. (integer) 279  
  9. 127.0.0.1:6379> ttl key_b  
  10. (integer) 591  
  11. //将key_a重命名为key_b  
  12. 127.0.0.1:6379> rename key_a key_b  
  13. OK  
  14. //新的key_b继承了key_a的过期时间  
  15. 127.0.0.1:6379> ttl key_b  
  16. (integer) 248  

这里篇幅有限,我就不一一将key_a重命名到key_b的各个情况列出来,大家可以在自己电脑上试一下key_a设置了过期时间,key_b没设置过期时间这种情况。

5、使用EXPIRE/PEXPIRE设置的过期时间为负数或者使用EXPIREAT/PEXPIREAT设置过期时间戳为过去的时间会导致key被删除

EXPIRE:

  1. 127.0.0.1:6379> set key_1 value_1  
  2. OK  
  3. 127.0.0.1:6379> get key_1  
  4. "value_1"  
  5. //设置过期时间为-1  
  6. 127.0.0.1:6379> expire key_1 -1  
  7. (integer) 1  
  8. //发现key被删除  
  9. 127.0.0.1:6379> get key_1  
  10. (nil)  

EXPIREAT:

  1. 127.0.0.1:6379> set key_2 value_2  
  2. OK  
  3. 127.0.0.1:6379> get key_2  
  4. "value_2"  
  5. //设置的时间戳为过去的时间  
  6. 127.0.0.1:6379> expireat key_2 10000  
  7. (integer) 1  
  8. //key被删除  
  9. 127.0.0.1:6379> get key_2  
  10. (nil)  

6、EXPIRE命令可以更新过期时间

对一个已经设置了过期时间的key使用expire命令,可以更新其过期时间。

  1. //设置key_1的过期时间为100s  
  2. 127.0.0.1:6379> set key_1 value_1 ex 100  
  3. OK  
  4. 127.0.0.1:6379> ttl key_1  
  5. (integer) 95  
  6. //更新key_1的过期时间为300s  
  7. 127.0.0.1:6379> expire key_1 300  
  8. (integer) 1  
  9. 127.0.0.1:6379> ttl key_1  
  10. (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次过期扫描:

  • 从过期字典中随机20个key
  • 删除这20个key中已过期的
  • 如果超过25%的key过期,则重复第一步

同时,为了保证不出现循环过度的情况,Redis还设置了扫描的时间上限,默认不会超过25ms。

参考资料

https://redis.io/commands/expire#expire-accuracy

延伸 · 阅读

精彩推荐
  • Redis就这?Redis持久化策略——AOF

    就这?Redis持久化策略——AOF

    今天为大家介绍Redis的另一种持久化策略——AOF。注意:AOF文件只会记录Redis的写操作命令,因为读命令对数据的恢复没有任何意义...

    头发茂密的刘叔4052021-12-14
  • Redis聊一聊Redis与MySQL双写一致性如何保证

    聊一聊Redis与MySQL双写一致性如何保证

    一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。本文给大家分享Redis与MySQL双写一致性该如何保证,感兴趣的朋友一...

    mind_programmonkey6432021-08-12
  • Redis在ssm项目中使用redis缓存查询数据的方法

    在ssm项目中使用redis缓存查询数据的方法

    本文主要简单的使用Java代码进行redis缓存,即在查询的时候先在service层从redis缓存中获取数据。如果大家对在ssm项目中使用redis缓存查询数据的相关知识感...

    caychen8962019-11-12
  • RedisLinux Redis 的安装步骤详解

    Linux Redis 的安装步骤详解

    这篇文章主要介绍了 Linux Redis 的安装步骤详解的相关资料,希望大家通过本文能掌握如何安装Redis,需要的朋友可以参考下 ...

    carl-zhao3822019-11-08
  • Redisredis启动,停止,及端口占用处理方法

    redis启动,停止,及端口占用处理方法

    今天小编就为大家分享一篇redis启动,停止,及端口占用处理方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    澄海单挑狂5152019-11-14
  • RedisRedis数据结构之链表与字典的使用

    Redis数据结构之链表与字典的使用

    这篇文章主要介绍了Redis数据结构之链表与字典的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友...

    白泽来了4052021-08-03
  • RedisRedis分布式锁升级版RedLock及SpringBoot实现方法

    Redis分布式锁升级版RedLock及SpringBoot实现方法

    这篇文章主要介绍了Redis分布式锁升级版RedLock及SpringBoot实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以...

    等不到的口琴7802021-07-25
  • RedisRedis存取序列化与反序列化性能问题详解

    Redis存取序列化与反序列化性能问题详解

    这篇文章主要给大家介绍了关于Redis存取序列化与反序列化性能问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    这名字已经存在9742021-02-24