redis服务器构造、数据库构造、客户端构造对理解每个功能来说非常重要。
Redis服务器构造
struct redisServer{
//一个数组,保存服务器中的所有数据库
redisDb *db;
//服务器的数据库数量
int dbnum;
}redisServer
服务器中的数据库构造
typedef struct redisDb{
//数据库键空间,保存数据库中的所有键值对,字典结构
dict *dict;
//过期时间存放在expire字典里
dict *expires;
}redisDb
从上面可以看出,数据库的dict指向的字典是一个键空间,也就是说所有的键都存放在数据库的dict指针指向的位置。键空间包含了五种类型的键。
客户端构造
typedef struct redisClient{
//记录当前客户端正在使用的数据库,指向服务器中的db数组中的元素
redisDb *db;
}redisClient
设置键的过期时间或者生存时间
SETEX只能用于字符串键。TTL(time to life 秒单位)和PTTL(毫秒单位)查询还剩多长时间删除。
如何保存键的生存时间和过期时间?
设置过期时间:PEXPIREAT、EXPIRE、PEXPIRE、EXPIREAT这四个命令用来设置过期时间,但是其他三个命令是PEXPIREAT实现的。
保存过期时间:redisDb结构里的expire字典保存了数据库中的所有键的过期时间。字典的键是一个指针,指向键空间的对象(某个数据库键),值是一个long long类型的整数(过期时间)。
通过下面这个结构方便理解。
移除过期时间:persist命令,即是解除过期字典中的键和值之间的关联。
过期键判定:查看expires字典,或者调用is_expired函数。
过期键的删除策略
定时删除(对cpu不友好)、惰性删除(对内存不友好)、定期删除(cpu和内存双不友好,难点是确定删除操作执行的时长和频率,执行时间太长 频率高 耗费CPU,执行时间太短、频率低对内存不友好)。
定时删除要用到redis服务器中的时间事件(无序链表实现)复杂度为O(N)。
Redis的过期删除策略:用的是惰性删除和定期删除配合使用,在内存和cpu之间取得平衡。
惰性删除策略的实现:所有读写数据库的命令在执行之前都调用expireifneeded函数。
定期删除策略的实现:多次遍历各个数据库随机检查,current_db会记录当前函数检查进度,下一次检查直接延续下去。
AOF和RDB复制功能对过期键的处理
生成RDB文件:用SAVE和BGSAVE创建一个RDB文件,过期的不会被保存到RD文件中。
载入RDB文件(将RDB变成数据库):过期键对主服务器不会造成影响、从服务器存储过期键,但是在和主服务器同步时,过期键会被清空。
AOF文件写入:AOF存储命令,过期键不会对其有影响。因为删除过期键的命令也会写入AOF
复制:主服务器删除后会向所有从服务器发送一个EDL命令。从服务器不会删除,除非接受到主服务器的del命令。