Redis 数据库

一、服务器中的数据库

struct redisServer{
    ....
    redisDb *db;
    int dbnum;
    ....
};
  • 所有数据库都保存在db 数组中,db 数组的每一项都是一个redisDb结构
  • 每个 redisDb 代表一个数据库
  • dbnum 在初始化服务器时确定该创建的服务器的数量

二、切换数据库

默认情况下,redis 客户端的目标数据库是 0 号数据库。可以通过 select 命令来切换目标数据库。

typedef struct redisClient{
    redisDb *db;
}redisClient;

>select 2 //切换到 2 号数据库

redisDb *db 指向redisServer.db 数组中的一个元素。

三、数据键空间

redis服务器中的每个数据库都由一个redis.h/redisDb结构表示。其中,redisDb 结构的字典保存了数据库中所有的键值对,这个字典称为键空间。

typedef struct redisDb{
    ...
    dict *dict;
    ...
}redisDb;

键空间的键就是数据库的键

键空间的值就是数据库的值

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

1、设置生存过期时间

//将键的生存时间设置为 ttl 秒
>EXPIRE <key> <ttl>
//将键的生存时间设置为 ttl 毫秒
>PEXPIRE <key> <ttl>
//将键的过期时间设置为 TIMESTAMP指定的秒数时间戳
>EXPIREAT <key> <timestamp>
//将键的过期时间设置为 TIMESTAMP指定的毫秒数时间戳
>PEXPIREAT <key> <timestamp>

EXPIRE、PEXPIRE和 EXPIREAT 最终都是由 PEXPIREAT 实现的。

2、保存过期时间

typedef struct redisDb{
    ....
    //过期字典,保存过期时间
    dict *expires;
    ...
}redisDb;

expires 字典保存了所有键的过期时间。

3、移除过期时间

>PERSIST message

PERSIST 是PEXPIREAT 的相反操作。

PERSIST命令在过期字典中查找给定的键,并解除键和值(过期时间)在过期字典中的关系。

4、计算并返回剩余生存时间

TTL命令:·以秒为单位返回键的剩余生存时间

PTTL 命令:以毫秒为单位返回键的剩余生存时间

都是通过获取键的过期时间,和当前时间相减计算出来的。

5、过期键的判断

1)检查给定键是否存在于过期字典:如果存在,那么取得键的过期时间

2)检查当前 UNIX时间戳是否大于键的过期时间,如果是,那么键已过期,否则键未过期

五、过期键的删除策略

  • 定时删除:用定时器在过期时间到来时删除,对内存友好,但是会占用 cpu 时间
  • 惰性删除:放任不管,当取出该键时进行检查删除,对 cpu 时间友好,但是会占用内存
  • 定期删除:每隔一段时间进行检查和删除,前两种策略的折中,需要合理的设置执行时长和频率

六、AOF、RDB和复制功能对过期键的处理

1、生成 RDB 文件

执行SAVE 或者BGSAVE创建一个新的 RDB 文件时,已过期的键不会被保存到新的 RDB 文件中。

2、载入 RDB 文件

如果服务器以主服务器模式运行,则只会载入未过期的键

如果服务器以从服务器模式运行,则RDB 文件中所有键都会载入。

3、AOF 文件写入

当服务器以 AOF 持久化模式运行时,如果有键过期但未删除,那么 AOF 文件不会受到影响。

当过期键被删除后,程序会向 AOF 文件追加一条 DEL 命令。

4、AOF 重写

在执行 AOF 重写的过程中,程序会对数据库中的键进行检查,已过期的键将不会被保存到重写后的 AOF 文件中。

5、复制

服务器在复制模式下,从的过期删除由主来控制。

当从没有收到主发送的 DEL message 命令时,就算键已过期,也会返回结果给 GET 命令。只有接受了主发送的 DEL 之后,从才会删除过期键。

七、数据库通知

数据库通知可以让客户端通过订阅给定频道或者模式,来获取数据库中键的变化,以及命令执行情况。

1、发送通知

void notifyKeyspaceEvent(int type,//发送通知类型
                         char *event,//事件名称
                         robj *key,//产生事件的键
                         int dbid);//数据库号码

当 redis 命令需要发送数据库通知的时候,该命令就会调用

notify-KeyspaceEvent函数。

2、notifyKeyspaceEvent函数操作:

1)检查通知类型是否允许,不允许则直接返回

2)检测服务器是否允许发送键空间通知,允许的话,程序就会构建并发送事件通知

3)最后,函数检测服务器是否允许发送键事件通知