数据库键空间
Redis服务器中的每个数据库都由redisDb表示,其中,redisDb结构的dict字典保存了数据库中的所有键值对,这个字典就成为键空间:
typedef struct redisDb{
......
dict *dict;
......
}redisDb;
下图是一个数据库键空间的示例图:
《Redis底层数据结构-字典》中详细地讲解过字典数据结构,字典包含多个键值对,字典的底层实现是哈希表,一个哈希表包含了多个哈希表节点,每个哈希表节点就保存了字典中的一个键值对。上图所示中,字典包含三个键值对,每个键中包含一个或多个值,键的对象类型是字符串对象,值的对象类型可以是字符串对象、列表对象、哈希对象、集合对象、有序集合对象,每个对象的至少包含两种底层数据结构。具体见《Redis五种数据类型的底层实现总结》
设置键的过期时间
Redis有四种命令设置键的过期时间:
- expire key ttl:将key的生存时间设置为ttl秒
- pexpire key ttl:将key的生存时间设置为ttl毫秒
- expireat key timestamp:将key的过期时间设置为timestamp所指定的秒数时间戳
- pexpireat key timestamp:将key的过期时间设置为timestamp所指定的毫秒数时间戳
但是最终的底层实现都和pexpireat 命令一样
保存过期时间
redisDb结构中的expires字典保存所有键的过期时间,这个字典称为过期字典
typedef struct redisDb{
......
dict *dict;
dict *expires;
......
}redisDb;
下图为带有过期字典的数据库示例:
新增/删除键的过期时间都表现为对过期字典的删除和添加节点操作。
过期键删除策略
如果一个键过期了,那什么时候被删除呢?
这里有三种策略:
- 定时删除:在设置键的过期时间的同时,创建一个定时器( timer ). 让定时器在键的过期时间来临时,立即执行对键的删除操作。
缺点:资源太多CPU时间 - 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
缺点:浪费内存,有内存泄漏的危险 - 定期删除: 每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库, 则由算法决定。
Redis采用惰性删除和定期删除两种策略结合,在执行所有读写数据库的命令前做如下判断:
并且,周期地执行定时删除函数,工作流程为: