具体结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct redisServer {
// 一个数组,保存着服务器中所有的数据库
redisDb *db;

// 服务器数据库的数量
int dbnum;
}

typedef struct redisClient {
// 记录客户端当前正在使用的数据库
redisDb *db;

} redisClient;

typedef struct redisDb {
// 数据库键空间,保存着数据库中的所有键值对
dict *dict;

} redisDb;

一个具体结构如下:

image-20230323111004847

image-20230323112514862

总的来说,就是一个redis实例,会有一个redisServer结构体,该结构体中db是一个数组,数组每一个元素代表一个数据库,每个db结构体就是一个具体的存放键值对的数据库。每一个redisClient结构体代表了一个客户端,该客户端指针会指向redisServer结构体db数组中的一个,代表使用该数据库。其中dict就是用户直接看到的数据库。

数据库键的一些操作

读写键空间时的维护操作

1、在读取一个键后,服务器会根据键是否命中来更新服务器键空间命中次数或者见空间不命中的次数。

2、在读取一个键后,服务器会更新键的LRU(最后一次使用)时间,这个值可以用于计算闲置时间。

3、如果服务器读取一个键发现已经过期,则会删除该键。

4、如果客户端使用watch命令监视某个键,那么服务器对被监视的键进行修改后,会标记其为脏键。

5、服务器每修改一个键后,都会对脏键计数器的值加1,这个计数器会触发服务器的持久化以及赋值操作。

6、如果服务器开启了数据库通知功能,对键进行修改后,会按配置发送给相应的数据库通知。

设置键的生存时间或过期时间

如何保存过期时间

redisDb结构的expires字典保存了数据库中所有键的过期时间,我们称之为过期字典。

过期字典的键是一个指针,指向键空间中的某个键对象。值是一个long long类型的整数,保存了过期时间。

具体如下:

image-20230323141113896

expires指向另外的一个字典,这个字典里面存储了每一个值的过期时间。

如何判断键是否过期

首先看过期字典中是否含有该键,如果存在,获取过期时间,与当前时间对比做判断,如果小于当前时间,则说明过期。

过期键删除策略

定时删除

在设置键过期时间的同时,创建一个定时器,让定时器在键过期时立即执行对键的删除。

优点:对内存友好,过期后会被立马删除。

缺点:对cpu不友好,如果过期键设置的太多,则定时器会占用太多的cpu资源。

惰性删除

只有在用到该键时,才取检查它是否过期,过期则删除,否则返回。

优点:不占用cpu资源。不会影响到redis处理客户端的请求。

缺点:会造成内存泄漏。如果一个键过期,它如果没有被再次访问,则无法删除。

定期删除

每隔一段时间,程序就检查一次数据库,删除里面的过期键,至于检查多少以及删除多少,由算法决定。

该算法的好坏取决于设定,不能太频繁的去删除,导致cpu资源浪费在了检索以及删除过期数据,也不能太长时间不删除导致里面很多过期数据。

Redis过期键删除策略

redis是将惰性删除和定期删除这两种策略配合使用。

惰性删除就是每次读写数据库命令执行前,都会调用一个函数检查键是否过期。

定期删除函数每次运行时,都会抽取一定量的随机键进行检查,并删除其中过期的键。有一个全局变量current_db会记录当前检查的进度,下次定期删除时会从这里开始。当服务器中数据都被检查一边时,这个值会被设置为0。

AOF和RDB以及复制对过期键的处理

生成RDB文件

在执行SAVE或者BGSAVE命令创建一个RDB文件时,会对数据库的键进行检查,已经过期的不会写入RDB文件。

载入RDB文件

如果以主服务器的模式加载RDB文件,则会对键进行检查,过期的不会载入。

如果以从服务器模式运行,则会保留所有键,不论是否过期。

AOF文件写入

当服务器采用AOF模式持久化,如果数据库某个键过期,但是还没被删除,则对AOF文件没有影响,但是删除时会向AOF文件中追加该记录被删除的命令。

AOF重写

AOF重写的过程中会进行检查,过期键不会保留。

复制

当服务器运行在复制模式下,从服务对过期键删除动作由主服务器控制:

1、主服务器删除一个过期键后,会向所有从服务器发送一条命令,通知其删除。

2、从服务器在接受到读命令时,尽管碰到过期键也不会删除,而是返回。(这本书创作时对应的redis版本最高为3.0,而后续高版本的redis在某些配置下会删除从服务上的过期键,但是删除从服务器数据后并不会主动删除主服务器的过期数据)

3、从服务器接收到主服务命令后才会删除过期键。

这样设置的目的是为了保存数据的一致性。

参考

《Redis设计与实现》