redis系列:数据库的实现

服务端数据库

redis中将所有的数据库信息保存在redisServer结构体中,结构体中的变量有两百多个,这里就不写了。
主要的结构成员是:

1
2
3
struct redisServer{
redisDb* db;
};

db成员指向一个redisDb数组,数组长度有dbnum决定:

默认情况下,目标数据库是0号数据库。如果需要更换数据库,修改指针即可。

数据库键空间

redisDb结构体中保存了数据库中所有的键值对,因此将这个字典称为键空间:

1
2
3
typedef struct redisDb{
dict* dict;
}
  • 键空间中的键是数据库的键,每个键都是一个字符串对象
  • 键空间中的值是数据库的值,每个值可以是一个字符串对象,列表对象,哈希表对象,集合对象,有序集合对象中的一种。
    表示如下图所示:

读写键空间时的维护操作

  • 读取一个键之后,服务器会更新键的LRU时间,这个可以用于计算键的闲置时间。
  • 如果在读取一个键时发现已经过期,服务器会删除这个过期键然后执行其他操作。
  • 如果客户端使用watch命令监视了某个键,会将这个键标记为脏,从而让事务程序注意到这个键已经被修改过。
  • 每次修改键之后,都会对脏键计数器加1,计数器会出发服务器的持久化和复制操作。
  • 如果开启数据库通知,在对键修改之后,服务器将按配置发送相应的数据库通知。

过期时间

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

  • 设置过期时间通过向过期字典添加键值对实现。
  • 删除过期时间则直接在过期字典中移除,移除策略有三种:
  1. 定时删除,创建过期时间的同时创建一个定时器,让定时器在键的过期时间删除;
  2. 惰性删除,每次获取键的时候检查是否过期;
  3. 定期删除,每隔一段时间主动删除过期键。

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

  1. RDB
  • 生成RDB文件时从数据库检查,过期不写入。
  • 载入RDB文件时:
    • 主服务器模式下会对所有键进行检查,过期忽略。
    • 从服务器模式会将所有键载入,不检查。
  1. AOF
  • 生成AOF:当服务器以AOF持久化模式运行时,如果某个键过期,但还没有被删除时,不会对AOF文件产生影响。当过期键被删除之后,程序会向AOF文件追加一条DEL命令,显式地记录该键已被删除。
  • 重写:进行键过期检查,过期则不写。
  1. 复制
  • 主服务器删除,向从服务器发送DEL命令。
  • 从服务器执行读命令,忽略键过期。
  • 从服务器接到DEL删除键。