一 .服务器中的数据库
Redis服务器将所有数据库都保存在服务器状态redisServer结构的db数组中,db数组中的每个项都是一个redisDb结构,每个redisDb结构代表一个数据库。
struct redisServer{
//一个数组,保存着服务器中的所有数据库
redisDb *db;
}
在初始化服务器时,程序会根据服务器状态的dbnum属性来决定创建多少个数据库,dbnum属性的值由database选项决定,默认情况下redis.conf配置文件中 databases=16;
二 .切换数据库
每个redis客户端都有自己的目标数据库,每次客户端执行数据库写命令或数据库读命令时,目标数据库就会成为这些命令的操作对象。默认情况下,Redis客户端的目标数据库是0号数据库。
切换数据库: select 2
在服务器内部,客户端状态redisClient结构的bd属性记录了客户端当前的目标数据库,这个属性是一个指向redisDb结构的指针。指针指向redisServer.db数组的其中一个元素,被指向的元素就是客户端的目标数据库。
typedef struct redisClient{
//记录客户端当前正在使用的数据库
redisDb *db;
}
比如,客户端的目标数据为2号数据库。
select原理:通过修改redisClient.db指针,让它指向服务器中的不同数据库,从而实现切换目标数据库的功能。
三, 数据库键空间
Redis是一个键值对数据库服务器,服务器中的每个数据库都由一个redisDb结构表示,redisDb结构的dict字典保存了数据库中所有键值对,这个字典就叫键空间
typedef struct redisDb{
//数据库键空间,保存数据库中所有的键值对
dict *dict;
}
所有对数据库增删该的操作都是通过对字典进行操作来实现的。
每次对数据库进行读写操作时,除了对键空间执行指定的读写操作,还会执行一些额外的维护操作。
在读取一个键之后,服务器会根据键是否存在来更新服务器的键空间命中次数或键空间不命中次数。
在读取一个键之后,服务器会更新键的LRU(最后一次使用)时间,这个值可以用来计算键的闲置时间,
如果服务器正在读取一个键时发现该键已经过期,那么服务器会先删除这个过期键,然后才执行相应的操作
四, 设置键的生存时间和过期时间
1.设置生存时间
expire/pexpire key 10
2.设置过期时间
expireat/pexpireat key 1377257300
注意:expire,pexpire,expireat这三个命令都是使用pexpireat来实现的。
3.保存过期时间
redisDb结构的expires字典保存了数据库中所有键的过期时间,expires字典的键指向键空间中的键对象,expires字典的值是一个long类型的整数(时间戳),表示过期时间
4.移除过期时间
在过期字典中查找给定的键,并解除键和值(过期时间)的关联
5.计算并返回剩余生存时间
ttl命令可以返回键的剩余生存时间
6.过期键的判断
取得键的过期时间:
如果键没有设置过期时间,返回 false
如果有过期时间,获取当前时间的时间戳:
如果当前时间大于过期时间,键过期
如果当前时间小于过期时间,键未过期
五,过期键的删除策略
定时删除:
在设置键的过期时间的同时,创建一个定时器(timer),当键的过期时间来临时,定时器立即执行对键的删除操作。
惰性删除:
每次从键空间中获取键时,都检查取得的键是否过期。如果过期就删除,没有过期就返回该键
定期删除:
每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键
六,Redis中过期键的删除策略
惰性删除和定期删除配合使用
通过定期删除策略,在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。
通过惰性删除策略,每次获取键都判断键是否过期。(所有Redis命令在执行之前都会调用expireifNeeded函数对输入键进行检查)。