设置生存时间和过期时间
- 设置生存时间----即让键在指定秒数或毫秒数之后过期
- expire key ttl---- expire key 5;即让键在5s后过期
- pexpire key ttl ---- pexpire key 6;即让键在6ms之后过期
- 设置过期时间—即让键在某一时刻过期
- expireat key timstamp — expire key 1377257300;让键在1377257300这个时刻过期
- pexpireat key timestamp ;以毫秒为单位。(前三个指令都会转换成这个指令)
- 可以通过ttl和pttl得到一个键剩余的生存时间。ttl以秒为单位返回,pttl以毫秒为单位返回。如 ttl key---->返回997,即表示key在997s之后过期。redis中time指令可以返回当前时刻的时间戳,以s为单位
保存过期时间
redisDb结构中的expires字典(dict * expires,即过期字典)保存了所有键的过期时间,该字典中,key是一个指向键空间(即dict *dict中包含的数据库中所有键值对)的指针,value是long long类型的整数,表示该键的过期时间。
typedef struct redisDb{ //数据库结构
//…
dict *dict; //存储键值对的字典
ditc *expire;//存储过期时间的字典,key指向dict中的key,value是一个longlong类型时间戳
}
下图中dict *expires字典中的键其实是指向dicet *dict中的键的,下图是单独画出来的,没展示出来,
pexpireat指令的实现伪代码。总体思路就是过期字典中添加一个dictEntry
def PEXPIREAT(key, expire_time_in_ms):
//如果该键不再键空间中,则不能取消过期时间
if key not in redisDb.dict:
return 0;
//移除过期字典中,给定键的键值对关联
redisDb.expires.remove(key);
return 1;
移除过期时间
persist key – > 将该键设置的过期时间取消。实现方式是,在expires字典中找到该key,然后解除键和值(过期时间)在过期字典中的关联。(即在过期字典中删除对应的dictEntry)
def PERSIST(key, expire_time_in_ms):
//如果该键不再键空间中,则不能设置过期时间
if key not in redisDb.dict:
return 0;
//在过期字典中关联键和过期时间
redisDb.expires[key] = expire_time_in_ms;
return 1;
``
键的过期删除策略
- 所有删除策略
- 定时删除:
(1)方式:在设置键的过期时间同时,创建一个该键的定时器,当达到过期时间时,立即删除该键。
(2)优点:对内存友好。过期时间已到达,就删除过期键,这样可以立即释放内存。
(3)缺点:CPU不友好。当过期键比较多,那么删除键需要占用大量cpu时间;创建定时器需要用到时间时间,时间事件的实现方式是无序链表,查找一个过期事件的复杂度为O(n),耗时。 - 惰性删除:
(1)方式:每次访问键时,才检查是否过期,如果过期就删除该键。
(2)优点:CPU友好。只有在访问该键时,才进行过期检查,并且删除的目标只针对于该键,不会在其他无关键上浪费CPU资源。
(3)缺点:内存不友好。当一个键过期后,而且也没有被访问,那么该键会一直保存在数据库中。即内存泄露。 - 定期删除:
(1)方式:每个一段时间,对数据库进行检查,删除过期键。定期删除是对定时删除(删除的太勤)和惰性删除(删除的太慢)的折中,每隔一段时间就进行数据库检查,删除那些过期的键,可以设置删除操作的时长和频率。
- 定时删除:
- Redis采用惰性删除和定期删除策略。
(1)惰性删除实现方式:在Redis命令执行之前,都会调用expireIfNeeded函数对输入键进行检查:
情况1:如果该键已经过期,那么将输入键删除。
情况2:如果未过期,则该函数不做任何动作。
(2)定期删除策略实现方式:当redis服务器中serverCron函数执行时,会调用activeExpireCycle函数,该函数在规定时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除过期键。