Redis中设置了过期时间的Key,有哪些需要注意的事项?

本文详细解析Redis中key过期时间的设置与管理,包括DEL、SET等命令对过期时间的影响,以及Redis如何通过懒惰删除和定期删除策略高效处理过期key。
熟悉Redis的同学应该知道,Redis的每个Key都可以设置一个过期时间,当达到过期时间的时候,这个key就会被自动删除。

 

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

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

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

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

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

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

(1)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

(2)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

1.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

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

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

//设置key_a的过期时间为300s
127.0.0.1:6379> set key_a value_a ex 300
OK
//设置key_b的过期时间为600s
127.0.0.1:6379> set key_b value_b ex 600
OK
127.0.0.1:6379> ttl key_a
(integer) 279
127.0.0.1:6379> ttl key_b
(integer) 591
//将key_a重命名为key_b
127.0.0.1:6379> rename key_a key_b
OK
//新的key_b继承了key_a的过期时间
127.0.0.1:6379> ttl key_b
(integer) 248

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

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

(1)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)

(2)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)

1.6 EXPIRE命令可以更新过期时间

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

//设置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

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

02 Redis的过期策略

那你有没有想过一个问题,Redis里面如果有大量的key,怎样才能高效的找出过期的key并将其删除呢,难道是遍历每一个key吗?假如同一时期过期的key非常多,Redis会不会因为一直处理过期事件,而导致读写指令的卡顿。

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

实际上Redis使用懒惰删除+定期删除相结合的方式处理过期的key。

2.1 懒惰删除

所谓懒惰删除就是在客户端访问该key的时候,redis会对key的过期时间进行检查,如果过期了就立即删除。

这种方式看似很完美,在访问的时候检查key的过期时间,不会占用太多的额外CPU资源。但是如果一个key已经过期了,如果长时间没有被访问,那么这个key就会一直存留在内存之中,严重消耗了内存资源。

2.2 定期删除

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

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

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

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

 

 

 

 

 

<think>嗯,用户问的是Redis有没有办法查看没有设置过期时间key。首先,我需要回忆一下Redis的命令和相关工具。记得Redis本身没有直接的命令可以列出所有没有过期时间key,不过可以通过一些组合的方法来实现。 首先,用户可能在使用Redis时,有些key设置过期时间,有些没有。他们可能需要找出那些永久的key,可能是为了优化内存,或者检查是否有遗漏设置过期时间的情况。用户的需求可能是管理内存,避免内存被无限制的key占用,尤其是在接近maxmemory限制时。 接下来,考虑解决方法。常用的方法包括使用SCAN命令结合TTL检查。SCAN可以迭代所有key,然后对每个key检查TTL,如果返回-1表示没有设置过期时间。但是,这种方法在数据量大的时候会比较慢,尤其是当key数量很多时,可能会影响性能。需要提醒用户谨慎在生产环境使用,避免阻塞。 另外,可能还需要提到使用Redis的Lua脚本,这样可以在服务器端执行,减少网络传输的开销,但同样需要注意脚本的执行时间,避免长时间阻塞。还有第三方工具,比如redis-rdb-tools,可以分析RDB文件,导出所有key的信息,包括过期时间。这对于离线分析比较安全,但需要生成和下载RDB文件,步骤稍多。 用户可能有不同的使用场景,比如开发环境可以接受慢查询,而生产环境需要更谨慎。需要根据具体情况建议不同的方法。同时,要提醒用户避免使用KEYS命令,因为会导致阻塞,即使是在测试环境,也应该用SCAN代替。 另外,用户可能不知道如何编写脚本或者使用第三方工具,所以需要给出具体的命令示例,比如shell脚本结合redis-cli,或者Lua脚本的例子。这样用户可以直接复制使用,提高实用性。 还需要考虑权限问题,是否有权限执行SCAN或Lua脚本,以及是否有权限访问RDB文件。同时,数据量大的情况下,处理时间可能很长,需要预估时间,并建议在低峰期操作。 最后,总结一下可行的几种方法,各自的优缺点,让用户根据自己的情况选择最合适的方案。同时强调注意事项,比如生产环境的谨慎操作,避免性能影响。</think>Redis **没有内置命令直接列出所有未设置过期时间Key**,但可以通过以下方法间接实现: --- ### **方法1:使用`SCAN` + `TTL`组合命令(推荐)** **原理**:遍历所有Key,检查每个Key的TTL(生存时间)。若`TTL key`返回`-1`,表示该Key设置过期时间。 #### **操作步骤(示例)** ```bash # 使用Shell脚本迭代所有Key并筛选未设置过期时间Key redis-cli --scan --pattern '*' | while read key; do ttl=$(redis-cli ttl "$key") if [ $ttl -eq -1 ]; then echo "$key" fi done ``` #### **注意事项** - **性能影响**:Key数量较多时,此操作会消耗大量时间和CPU,**避免在生产环境直接执行**。 - **替代`KEYS`命令**:必须用`SCAN`代替`KEYS *`,防止阻塞Redis服务。 --- ### **方法2:使用Lua脚本(效率更高)** 通过Lua脚本在Redis服务端执行扫描,减少网络传输开销: ```lua -- 执行以下脚本,返回所有未设置过期时间Key local keys = redis.call('SCAN', 0, 'MATCH', '*', 'COUNT', 1000) -- 分批次扫描 local result = {} for _, key in ipairs(keys[2]) do if redis.call('ttl', key) == -1 then table.insert(result, key) end end return result ``` #### **执行命令** ```bash redis-cli --eval find_keys_without_ttl.lua ``` --- ### **方法3:使用第三方工具分析RDB文件** 通过解析Redis的持久化文件(RDB)获取所有Key过期时间信息: 1. **生成RDB文件**: ```bash redis-cli save # 阻塞式生成RDB # 或 redis-cli bgsave # 后台生成RDB ``` 2. **使用工具分析**: 安装`redis-rdb-tools`: ```bash pip install rdbtools ``` 导出所有Key及其过期时间: ```bash rdb --command json dump.rdb | jq 'select(.expiration == null) | .key' ``` --- ### **适用场景对比** | 方法 | 优点 | 缺点 | 适用场景 | |------------|-------------------------------|-----------------------------------|------------------------| | `SCAN+TTL` | 无需额外工具 | 速度慢,可能影响生产环境性能 | 测试环境或小规模数据 | | Lua脚本 | 减少网络延迟,效率较高 | 仍可能阻塞Redis | 中低负载环境 | | RDB分析 | 安全,完全不影响线上服务 | 需要停机或等待RDB生成,步骤较复杂 | 离线分析或大数据量场景 | --- ### **关键提醒** 1. **生产环境谨慎操作**:避免直接使用`KEYS *`或全量扫描,优先选择低峰期操作。 2. **内存管理建议**:未设置过期时间Key可能导致内存无限增长,建议: - 对长期有效的数据**显式设置过期时间**(如`EXPIRE key 10年`)。 - 定期清理无用Key
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值