redis过期时间
注意事项
-
DEL/SET/GETSET等命令会清除过期时间
在使用 DEL、SET、GETSET 等会覆盖key对应value的命令操作一个设置了过期时间的key的时候,会导致对应的key的过期时间被清除。 -
INCR/LPUSH/HSET等命令则不会清除过期时间
而在使用 INCR/LPUSH/HSET 这种只是修改一个key的value,而不是覆盖整个value的命令,则不会清除key的过期时间。 -
PERSIST命令会清除过期时间
-
使用RENAME命令,老key的过期时间将会转到新key上
例如: RENAME KEY A KEY B 命令将KEYA重命名为KEYB,不管KEYB有没有设置过期时间,新的key KEYB将会继承KEY_A的所有特性。
这里篇幅有限,我就不一一将keya重命名到keyb的各个情况列出来,大家可以在自己电脑上试一下keya设置了过期时间,keyb没设置过期时间这种情况。
- 使用EXPIRE/PEXPIRE设置的过期时间为负数或者使用EXPIREAT/PEXPIREAT设置过期时间戳为过去的时间会导致key被删除
EXPIRE:
EXPIREAT:
- EXPIRE命令可以更新过期时间
对一个已经设置了过期时间的key使用expire命令,可以更新其过期时间。
在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。
redis实现频率限制
1)方案1 - Lua脚本
思路
把限制逻辑封装到一个Lua脚本中,调用时只需传入:key、限制数量、过期时间,调用结果就会指明是否运行访问
local notexists = redis.call(\"set\", KEYS[1], 1, \"NX\", \"EX\", tonumber(ARGV[2]))
if (notexists) then
return 1
end
local current = tonumber(redis.call(\"get\", KEYS[1]))
if (current == nil) then
local result = redis.call(\"incr\", KEYS[1])
redis.call(\"expire\", KEYS[1], tonumber(ARGV[2]))
return result
end
if (current >= tonumber(ARGV[1])) then
error(\"too many requests\")
end
local result = redis.call(\"incr\", KEYS[1])
return result
(2)方案2 - 扩展模块
Redis4 中开放了模块系统,大家可以开发自己的模块插入到 redis 中,redis 官方已经推荐了一个访问限制模块 redis-cell,只需要一条命令就可以实现需求
示例
CL.THROTTLE user123 15 30 60
复制
user123 是 key
15 是最大配额数量
30 是可以访问次数
60 是时间周期,单位秒
综合起来的意思是,user123 的最大资源配额是15,60秒内最多可以访问30次
返回结果:
- (integer) 0 # 0 允许; 1 拒绝
- (integer) 16 # 总配额
- (integer) 15 # 剩余配额
- (integer) -1 # 几秒后可以重试,-1 表示不限制,第一条为0时,此处为-1
- (integer) 2 # 几秒后恢复最大值
复制
每次执行这个命令时,剩余配额都会减1,当配额不足,或者访问次数超限时,都会被拒绝
项目地址
https://github.com/antirez/neural-redis