Redis(十一):键的生存时间与过期时间
redisDB 结构(数据库)的 expires 字典保存了数据库所有键的过期时间(使用字典去实现保存过期时间),称这个字典为过期字典
过期字典的键其实是一个指针,保存的是键空间里面的键值对对象
过期字典的值其实是一个 Long long 类型的整数,这个整数保存了过期时间(一个毫秒精度的 unix 时间戳)
typedef struct redisDB(
//键空间
dict *keyspace;
//过期字典
dict *expires;
)redisDB;
可以使用命令来移除指定键的过期时间
//移除指定键的过期时间
persist key
PERSIST 其实就是 PEXPIREAT 的反向操作,PERISIST 在过期字典中查找给定的键,然后解除键和值在过期字典中的关联,也就是在过期字典中删除这个键值对
前面提到过,可以使用 TTL 命令以秒为单位返回键的剩余生存时间,而 PTTL 命令则以毫秒为单位返回键的剩余生存时间
ttl key
pttl key
TTL 和 PTTL 这两个命令都是通过计算键的过期时间和当前时间之间的差来实现的
PTTL 的实现原理
前面已经说过,设置过期时间的命令最终都会变成 pexpireat,使用的参数是毫秒级别的 unix 时间戳,所以只要通过设置的 unix 时间戳减去当前时间的时间戳,就可以得到剩余的生存时间(都要转换成毫秒级别)
TTL 的实现原理
前面与 PTTL 一样,只不过返
回的时候将毫秒转换成秒而已。
特殊返回值
键不在数据库时候,会返回**-2**
键没有设置过期时间,会返回**-1**
通过过期字典,Redis 通过以下步骤来判定过期键
检查给定键是否在过期字典中,存在就取键的过期时间
检查当前 UNIX 时间戳是否大于键的过期时间(UNIX 时间戳),如果是的话,那么键就已经过期,否则的话,键未过期。
当一个键过期的时候,Redis 将会根据删除策略去决定删除过期键的时间和方式
总共有三种删除策略
定时删除:在设置键的过期时间的同时,设置一个定时器,让定时器在键的过期时间来临时,会立即执行对键的删除动作
惰性删除:放任键过期不管,但是用户从键空间去取键的时候,都会检查取得的键是否过期,如果过期的话,就删除该键,并且返回 nil,如果没过期的话,就返回该键
定期删除:每隔一段时间就去对数据库进行检查,删除里面的过期键,要删除多少过期键或是对哪些数据库进行检查,由使用的算法规定
定时删除
定时删除的优点就是可以第一时间删除过期的键,这对于内存来说是十分友好的,可以及时释放不要的对象来节约内存
但定时删除的缺点也是第一时间去删除过期的键,假如存在大量的键都在同一时间过期,那么在这一段时间就会占用一部分的 CPU,这段时间的服务器性能就会下降,降低了数据的吞吐量,严重的话会发生停止服务的行为。
除此之外,创建定时器需要用到 Redis 服务器中的时间事件,而时间事件的实现方式为无序链表,要找到某一刻的时间事件需要遍历无序链表,时间复杂度为 O ( N ) O(N) O(N)
因此这是不现实的
惰性删除
惰性删除对于 CPU 的占用是友好的,只有要找键值对的时候才进行判断删除,实现了就是到了万不得已的时候,才会去删除该键,并且不会去删除其他键,对 CPU 的占用可以是忽略不计
但缺点也就是要到万不得已的时候,才去删除,这对内存是不友好的,假如键过期了,然后用户那边不访问,这个键就会一直在内存中,占着资源,如果过期键很多很多,而且又不会再被访问,那么占用的内存就更多了。
对于内存数据库来说,这肯定也会造成影响
定期删除
定期删除就比较综合了,综合了定时删除和惰性删除的优点
定时删除占用 CPU,惰性删除占用内存
定期删除是每隔一定时间,对指定数据库,删除指定数量的过期键
每隔一定时间才去执行,限制删除的数量,和扫描的数据库,减少了 CPU 的占用
定期去删除过期键,节约了内存
评论