Redis 数据库
数据库
本章将对 Redis 数据库的构造和实现进行讨论。
除了说明数据库是如何储存数据对象之外,本章还会讨论键的过期信息是如何保存,而 Redis 又是如何删除过期键的。
数据库的结构
Redis 中的每个数据库,都由一个 redis.h/redisDb
结构表示:
typedef struct redisDb {
// 保存着数据库以整数表示的号码
int id;
// 保存着数据库中的所有键值对数据
// 这个属性也被称为键空间(key space)
dict *dict;
// 保存着键的过期信息
dict *expires;
// 实现列表阻塞原语,如 BLPOP
// 在列表类型一章有详细的讨论
dict *blocking_keys;
dict *ready_keys;
// 用于实现 WATCH 命令
// 在事务章节有详细的讨论
dict *watched_keys;
} redisDb;
下文将详细讨论 id
、 dict
和 expires
三个属性,以及针对这三个属性所执行的数据库操作。
数据库的切换
redisDb
结构的 id
域保存着数据库的号码。
这个号码很容易让人将它和切换数据库的 SELECT 命令联系在一起,但是,实际上,id
属性并不是用来实现 SELECT 命令,而是给 Redis 内部程序使用的。
当 Redis 服务器初始化时,它会创建出 redis.h/REDIS_DEFAULT_DBNUM
个数据库,并将所有数据库保存到 redis.h/redisServer.db
数组中,每个数据库的 id
为从 0
到 REDIS_DEFAULT_DBNUM - 1
的值。
当执行 SELECT number
命令时,程序直接使用 redisServer.db[number]
来切换数据库。
但是,一些内部程序,比如 AOF 程序、复制程序和 RDB 程序,需要知道当前数据库的号码,如果没有 id
域的话,程序就只能在当前使用的数据库的指针,和 redisServer.db
数组中所有数据库的指针进行对比,以此来弄清楚自己正在使用的是那个数据库。
以下伪代码描述了这个对比过程:
def PSEUDO_GET_CURRENT_DB_NUMBER(current_db_pointer):
i = 0
for db_pointer in redisServer.db:
if db_pointer == current_db_pointer:
break
i += 1
return i
有了 id
域的话,程序就可以通过读取 id
域来了解自己正在使用的是哪个数据库,这样就不用对比指针那么麻烦了。
数据库键空间
因为 Redis 是一个键值对数据库(key-value pairs database),所以它的数据库本身也是一个字典(俗称 key space):
在 redisDb
结构的 dict
属性中,保存着数据库的所有键值对数据。
下图展示了一个包含 number
、 book
、 message
三个键的数据库 ——其中 number
键是一个列表,列表中包含三个整数值;book
键是一个哈希表,表中包含三个键值对;而 message
键则指向另一个字符串: