Skip to content

Redis设计与实现之数据库

1185字约4分钟

数据库

2021-12-05

数据库的存储

数据库保存在 server.h/redisServer结构的redisDb *db中 , 其结构如下:

服务器中的数据库

redisServer中,存储了一个数据库列表, 在服务启动时, 会根据 dbnum 大小决定创建多少个数据库, dbnum大小有服务器配置的 database选项 决定, 默认值为 16

数据库的定义

代码定义在: server.h/redisDb

// redis数据库的定义
typedef struct redisDb {
    dict *dict;                 /* 数据库的 keyspace */
    dict *expires;              /* 带有过期时间的 keys */
    dict *blocking_keys;        /* 阻塞等待数据的keys (BLPOP)*/
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    dict *watched_keys;         /* 监控的 keys MULTI/EXEC CAS */
    int id;                     /* 数据库 ID */
    long long avg_ttl;          /* Average TTL, just for stats */
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;

切换数据库

每个 redis 客户端都有自己的目标数据库, 每个客户端读取数据库写入或者读取命令时,目标数据库回程问这些命令的操作对象.

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

下图演示了数据库切换的操作:

数据库切换操作示例

在服务器内部, 客户端 client(server.h/client) 结构的 db 属性,记录了客户端当前的目标数据库, 这个属性是一个指向 redisDb结构的指针

typedef struct client {
    // 其他属性省略
    redisDb *db;            /* 指向当前选中数据库的指针. */
} client;

client.db 只想的就是 server.db 中的一个元素, 而被指向的元素, 就是客户端的目标数据库.

重要

通过修改 client.db 的指针, 让它指向服务器中不同的数据库, 从而实现切换目标数据库的功能 , 这就是 SELECT 指令的实现原理

拓展思考

假设我们当前有16个数据库, 当前已经向 id = 15 的数据库中写入了数据, 此时出于种种原因, 调整 databases = 8 , 重启服务会发生什么呢?

此问题分三个场景

作为纯内存缓存数据库使用

因为时纯内存的数据库, 重启时, 会清空全部数据, 再次启动时,不会有任何影响, 但是如果客户端未升级, 选择的数据库 >= 8, 此时客户端会报错

开启了持久化

若开启了持久化, 由于服务启动时会从持久化文件恢复数据, 则会产生数据无法恢复的情况, 进而导致服务无法启动 , 具体报错如下:

开启持久化,缩减database数量示例

缩减数量的同时,关闭持久化

在缩减database数量同时,关闭数据持久化,作为内存缓存使用,又会怎么样?

如果 未删除之前持久化的文件dump.rdb, 则服务依旧无法启动, 报错信息同 开启了持久化 的场景

如果删除了持久化的文件, 则服务可以正常启动, 场景同 作为纯内存缓存数据库使用

参考资料

参考内容

书籍 : 《Redis 设计与实现》

实体书 : 可在京东搜索购买

注意事项

《Redis 设计与实现》 本书讲解基于redis 3.x 版本, 本人整理基于redis 5.0.6,期间跨了两个大版本, 部分功能具体实现已发生变化, 如发现整理内容与 《Redis 设计与实现》 讲解不一致, 可加 QQ : 2215508028 沟通,或在相关章节评论留言,会自动同步至issue

整理内容时参考的redis源码

版本 : 5.0.6

官方git : redis官方GIT (commit :bb78454b0fef0dc5903328d037ac2520108e0044 (5.0.6版本,redis官方的commit))