Redis中的数据库

如同MySQL等传统数据库一样,redis也有自己的各个不同的数据库,它们被保存在redisServer结构的redisDb数组当中,在初始化服务器的时候,程序会根据redisServer中的dbnum属性来决定创建多少个数据库(默认数量为16个)。实际上,redis的各个数据库就是用字典实现的一张大的Hash表,表的键是一个字符串对象,值可以是任何redis中的对象类型:哈希表对象,集合对象,有序集合对象,字符串对象,列表对象

切换数据库:
默认使用号数据库,使用select来执行数据库的切换。
格式 redis>select 数据库序号
实现原理:客户端结构redisClient

typedef struct redisClient{
//....
//记录正在使用的数据库
   redisDb *db;

}redisClient;

select指令通过让db指针指向不同的数据库元素来实现数据库的切换。

redis的键空间
redisDB中的字典保存了数据库中的所有键值对,我们将这个字典成为键空间
添加、删除、更新和取值的操作就是对字典进行一样,前文已经讲过不再赘述。
其他的针对数据库本身的Redis命令有:
FLUSHDB:删除所有键
RANDOMKEY:随机返回一个键
DBSIZE:返回键的数量
EXISTS:判断是否存在该键
RENAME:更改键名称

读写键空间的维护操作:
1. 每次读取会根据键是否存在来更新服务器的键命中次数
2. 读取一个键之后会更新键的LRU,这在内存吃紧的时候会通过LRU策略来进行键的删除
3. 如果读取的时候发现键已经过期,那么就会删除该键
4. 每次对一个键进行修改之后就将该键的dirty值+1,这个计数器会触发服务器的持久化操作
5. 如果开启了数据库通知功能,那个在键更改后会发送相应的数据库通知

设置键的生存时间或者过期时间
redis提供了几个API来对一个键进行生存时间的控制,因为需要,有秒级的时间控制也有毫秒级的时间控制。首先我们先来看个例子:

redis>SET  key value
OK

redis>EXPIRE key 5 (表示5秒后该键过期,不能继续使用)
(Integer)1

redis>GET key (五秒之内)
"value"

redis>GET key (五秒之后)
(nil)

下面来介绍API:
EXPIRE和PEXPIRE是来设计秒级的过期时间的
EXPIREAT和PEXPIREAT是用来设置毫秒级的过期时间的
但是实际上EXPIRE和PEXPIRE的底层也是由PEXPIREAT来实现的,只是为了应对需求增加的粗粒度的时间控制API。
EXPIREAT的过期时间是一个UNIX时间戳(格林威治1970.01.01 00:00 00:00 到现在的秒数 这里的UNIX时间戳是毫秒精度的)

关于过期时间的保存:

redisDb中的expires字典保存了数据库中所有键的过期时间,这个就是过期字典,它通过一个long long类型来保存键所指向的数据库的过期时间,这是个毫秒精度的UNIX时间戳(上文提及过EXPIRE和PEXPIRE的底层也是由PEXPIRE来实现的,所以只会保存毫秒级的时间不会保存秒级的)

移除过期时间
能设置自然也可以移除,通过 PERSIST key值 来移除一个键上的过期时间
计算并返回剩余的生存时间:TTL命令(返回秒级) PTTL(返回毫秒级)

过期时间的判定
1. 是否存在过期字典当中:如果存在取得过期时间
2. 检查当前的UNIX时间戳是否大于过期时间

过期键的删除策略
一共有三种关于过期键删除的策略
1. 定时删除:为每一个键设置一个定时器,当定时器到达过期时间就由服务器进行删除,对内存很友善但是这注定只是一种过于理想的策略,因为为每个键设定一个定时器这样的开销是CPU无法接受的,所以redis并没有实现这样的策略。
2. 懒惰删除:当键过期的时候,在查询的时候会返回空值,并且删除要查询的过期的键,但是如果一直没有查到这个键,那么它将在内存中一直存在,这对CPU是很友好的,可是却不安全,容易让过期的键一直存在于内存中发生内存泄露
3. 定期删除:老调重弹了,在redis中有许多的关于定时的策略,这个方式也不例外,定时删除就是指每经过一段时间就对各个数据库进行一次删除,但是不是完全删除,而是限制删除的时长和频率来减轻服务器的负担,这是一种比较折中的方式。

Redis的过期键删除策略:
Redis实际使用的是懒惰删除和定期删除来取得一种CPU和内存之间平衡的一种状态。

AOF、RDB和复制功能对过期键的处理
生成RDB文件:执行SAVE或者BGSAVE的时候,已经过期的键会被检查,不会被存在RBD文件当中,因此当数据库中包含过期的键的时候不会对RDB文件造成影响

载入RDB文件:
当服务器以主服务器运行时候,载入RDB文件时候会进行检查,已经过期的键不会被载入
当服务器以从服务器运行时候,所有的键都会被载入,无论是否过期。

AOF文件写入
AOF文件不会对没有进行惰性删除或者定期删除的键做出影响,不过一旦键被惰性删除或者定期删除那么就会将删除操作追加到AOF当中去。

AOF重写
和生成RDB类似,在进行AOF重写的时候程序会对数据库中的键进行检查,已经过期的不会被重新保存在AOF中。

关于复制:
从服务器的过期键的删除都是由主服务器负责,
一个有趣的例子:
当你向从服务查询一个还没有被删除的已经过期的键的时候,你会得到这个键对应的值,当你向主服务器发出同样的请求的时候,主服务会查询,哦,原来已经过期了啊,然后返回给你一个nil,并删除这个键,然后将删除的命令通知给所有的从服务器,所有从服务器也对该键进行了删除。