服务器中的数据库
Redis服务器将所有的数据库都u保存在服务器状态redis.h/redisServer结构的db数组中,db数组的每个项都是一个redis.h/redisDb结构,每个redisDb结构代表一个数据库
struct redisServer{
//一个数组,保存着服务器中的所有数据库
redisDb *db;
//服务器的数据库数量
int dbnum;
//记录客户端当前正在使用的数据库
redisDb *db;
//数据库键空间,保存着数据库中的所有键值对
dict *dict;
//过期字典
dict *expires;
}
在初始化服务器时,程序会根据服务器状态的dbnum属性来决定应该创建多少个数据库
dbnum的默认值为16
切换数据库
每个redis客户端都有自己的目标数据库,默认为0号,可以利用SELECT操作进行切换
谨慎处理多数据库程序
到目前为止,Redis仍然没有可以返回客户端目标数据库的命令。虽然redis-cli客户端会提示目前正在使用的数据库
但其他语言的客户端并没有这个功能,容易对数据库产生误操作
‘
数据库键空间
redisDb结构的dict字典保存了数据库中的所有键值对,我们将这个字典成为键空间
数据库的键空间是一个字典,所以所有针对数据库的操作,实际上都是通过对键空间字典进行操作来实现的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ac6aTzNC-1672997275530)(%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%88%E4%B8%80%EF%BC%89%2057b87a4d871842539a54d660505f0c79/Untitled.png)]
当使用Redis命令对数据库进行读写时,服务器不仅会对键空间执行指定的读写操作,还会进行一些额外的维护操作
(1)读取一个键后,服务器会更新服务器中的键空间命中次数或键空间不命中次数
(2)读取一个键后,服务器会更新键的LRU(最后一次使用)时间
(3)读取键时,如果发现此键已过期,会先删除这个过期键,然后才执行余下的其他操作
(4)如果有客户端进行WATCH命令监视了某个键,那么服务器在对被监视的键进行修改之后,会将这个键标记为脏
(5)服务器每修改一个键后,都会对脏键计数器的值赠一
设置键的生存时间或过期时间
通过EXPIRE命令或者PEXOPIRE命令,客户端可以以秒或者毫秒精度为数据库中的某个键设置生存时间
同样可以使用EXPIREAT命令或者是PEXPIREAT命令设置过期时间
服务器是如何设置过期时间的
redisBd结构的expires字典保存了数据库中所有键的过期时间,即过期字典
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MdeUyvMw-1672997275531)(%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%88%E4%B8%80%EF%BC%89%2057b87a4d871842539a54d660505f0c79/Untitled%201.png)]
移除过期时间
PERSIST是PEXPIREAT的反操作
计算并返回剩余生存时间
TTL和PTTL命令都是通过计算键的过期时间和当前时间的差来实现的
过期键的判定
通过过期字典使用以下步骤,可以判定一个键是否过期
(1)检查是否存在于过期字典
(2)检查当前UNIX时间戳是否大于键的过期时间
过期键的删除测试
(1)定时删除:在设置键的过期时间的同时,创建一个定时器
(2)惰性删除:放任过期键不管,但是每次从键空间中获取键时,都检查是否过期
(3)定期删除:每个一段时间,都会检查过期键并删除
Redis过期键的删除策略
实际上,Redis服务器使用的是惰性删除和定期删除两种策略
过期键的惰性删除策略由db.c/expirelfNEdded函数实现,所有读写数据库的Redis命令在执行之前都会调用该函数进行检查
该函数会在命令真正被执行前,删除掉过期键
过期键的定期删除策略由redis.c/activeExpireCycle函数实现,每当Redis的服务器周期性操作进行时,该函数就会被调用
它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库中的expires字典(即过期字典)中随机检查一部分键的过期时间,并删除过期键