本篇文章是redis系列中的第二大部分的开始,这一部分为数据库的实现,主要讲单节点的数据库知识。下边附上第一部分基础知识总结篇的链接,有需要的童鞋,欢迎查看。
redis–对象
redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组中每一个项都是一个redis.h/redisDb结构。
redisServer结构如下:
struct redisServer{
//一个数组,保存着服务器中的所有数据库
redisDb *db;
//服务器的数据库数量
int dbnum;
};
每个redis客户端都有自己的目标数据库,每当客户端执行命令时,目标数据库就会成为这些命令的操作对象。默认情况下为0号数据库,可以通过SELECT命令切换目标数据库。
typedef struct redisClient{
//记录客户端当前正在使用的数据库
redisDb *db;
}redisClient;
Redis是一个键值对数据库服务器,服务器中的每个数据库都由一个redis.h/redisDb结构表示,其中redisDb结构的dict字典保存了数据库中的所有键值对,我们称这个字典为键空间。
typedef struct redisDb{
//数据库键空间,保存着数据库中的所有键值对
dict *dict;
}redisDb;
键空间和用户所见的数据库是直接对应的:
这里我们新建一个字符串对象message,列表对象alphabet和哈希集合book,结构如下:
所有针对数据库的操作,都是通过对键空间字典进行操作实现的。清空整个数据库的FLUSHDB命令,就是通过删除键空间中的所有键值对来实现的。
当redis进行读写操作是,会对键空间执行以下维护操作。
通过EXPIRE命令或者PEXPIRE命令,客户端可以以秒或者毫秒精度为数据库中的键设置生存时间,经过指定的秒数或者毫秒数之后,服务器会自动删除生存时间为0的键。类似的EXPIREAT命令或者PEXPIREAT命令,设置过期时间;过期时间是UNIX时间戳,当键的过期时间来临时,服务器会自动删除这个键。
TTL命令和PTTL命令接受一个带有生存时间或者过期时间的键,返回这个键剩余生存时间。
EXPIRE命令,PEXPIRE命令和EXPIREAT命令,都是通过转换为PEXPIREAT命令来执行的。
redisDb结构的expires字典保存了数据库中所有键的过期时间。
策略 | 实现 | 优点 | 缺点 |
---|---|---|---|
定时 | 设置键的同时,设置定时器,到期立即删除 | 内存友好 | cpu不友好 |
惰性 | 每次获取时,删除已过期的键值对 | 内存不友好 | cpu友好 |
定期 | 每隔一段时间,对数据库检查一次,删除里边的过期键 | 折中 | 折中 |
定期策略的难点是确定删除操作执行的时长和频率,设置不好会退化成定时或者惰性策略。
redis使用惰性和定期两种策略。通过配合使用,在合理的利用cpu和避免内存浪费之间取得平衡。
在执行SAVE命令或者BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键进行检查,已经过期的键不会被保存到新创建的RDB文件中。
在启动redis服务器时,如果服务器开启了RDB功能,那么服务器将对RDB文件进行载入:
当服务器以AOF模式持久化运行时,如果数据库中的某个键已经过期,但它还没有被删除,那么AOF问价不会因为这个过期键而产生任何影响。当过期键被删除后,程序向AOF文件追加一条DEL命令,来显式的记录该键已被删除。
主要步骤如下:
和生成RDB类似,已过期的键不会被保存到重写后的AOF文件。
当服务器运行在复制模式下时,从服务器的过期键删除动作由主服务器控制。
在2.8版本之后,客户端可以通过订阅给定的频道或者模式,来获知数据库中键的变化。当redis命令对数据库进行修改后,服务器会根据配置向客户端发送数据库通知。服务器配置的notify-keyspace-events选项决定了服务器所发送通知的类型。