数据库
数据库与客户端
Redis服务器的所有数据库都保存在redisServer结构的db数组中,根据dbnum属性初始化数据库的数量;
struct redisServer{
//.....
//一个数组,保存服务器中的所有数据库
redisDb *db;
//服务器的数据库数量,默认16个
int dbnum;
}
切换数据库:select 1;
服务器的内部,客户端状态redisClient结构记录客户端的状态
typedef struct redisclient{
//记录客户端当前使用的数据库
redisDb *db;
}redisClient
数据库键空间
Redis是一个键值对(key-value pair)数据库服务器,服务器中的每个数据库信息由redisDb保存,其中有个属性dict字典保存所有的键值对,这个字典就是键空间。
typedef struct redisDb{
//数据库键空间,保存着数据库中所有键值对
dict *dict;
}
设置过期时间
EXPIRE KEY TTL:将键key的生存时间设置为ttl秒
PEXPIRE KEY TTL:将键key的生存时间设置为ttl毫秒
EXPIRE KEY TIMESTAMP:将键key的过期时间设置为timestamp所指定的秒数时间戳
PEXPIRE KEY TIMESTAMP:将键key的过期时间设置为timestamp所指定的毫秒数时间戳
PERSIST key:移除过期时间。
TTL:计算键的过期时间与当前时间之差,以秒为单位返回。
PTTL:计算键的过期时间与当前时间之差,以豪秒为单位返回。
redisDb结构的属性expires字典保存数据库中所有键的过期时间,这个字典称为过期字典。
typedef struct redisDb{
//过期字典,保存着键的过期时间
dict *expires;
}
过期键删除策略
键的过期删除策略有三种:
- 定时删除:主动删除,在设置键的过期时间的同时,创建一个定时器,让定时器在键过期时间来临的时候,立即对键进行删除操作;(内存友好)
- 惰性删除:被动删除,放任键过期不管,每次从键空间获取键的时候,都检查键是否过期,过期则删除。(CPU友好)
- 定期删除:主动删除,每隔一段时间,程序对数据库进行检查,删除里面的过期键。(折中处理方案)
在执行SAVE命令或者BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键进行检查,已过期的键不会保存到新创建的RDB文件中;
主服务器在载入RDB文件的时候,会对过期键进行筛选,不将过期的键录入,而从服务器在载入RDB文件的时候,会将过期的键也录入;
当服务器以AOF模式运行时,不会收到过期键的影响,当过期键被惰性删除或定期删除后,AOF文件会追加一条DEL命令来显式地删除该键。
AOF重写的时候,不会将过期的键写入文件。
复制模式下,从服务器不会主动去删除过期的键,都是由主服务器去控制,当主服务器向从服务器发送删除命令的时候,从服务器才回去删除过期的键。
RDB持久化
数据库状态:服务器中的非空数据库及其键值对
RDB文件:一个压缩的二进制文件,用来记录数据库状态
生成RDB文件
SAVE:阻塞Redis服务器进程,直到RDB文件创建完毕为止。
BGSAVE:命令会派生出子进程,由子进程去完成RDB文件创建,父进程继续响应命令处理。
AOF文件的更新频率会比RDB文件的更新频率高,所以如果服务器启动了AOF持久化功能,服务器会优先使用AOF文件还原数据库状态
自动间隔性保存
服务器默认的保存策略
SAVE 900 1:服务器在900秒内,对数据库进行了至少一次修改;
SAVE 300 10:服务器在300秒内,对数据库进行了至少10次修改;
SAVE 60 10000:服务器在60秒内,对数据库进行了至少10000次修改;
保存条件的数据结构
struct redisServer{
//记录保存条件的数组
struct saveparam *saveparams;
}
struct saveparam{
//秒数
time_t seconds;
//修改数
int changes;
}
RDB文件结构
redis | db_version | databases | eof | check_sum
redis:文件头,保存REDIS字符用于标识文件;
db_version:长度4字节 ,记录RDB文件版本号;
databases:包含零个或任意多个数据库,以及各数据库中的键值对数据;
保存的数据结构为:SELECTDB | db_number | key_value_pairs
eof:常量的长度为1字节,标识RDB文件正文结束;
check_sum:8字节长的无符号整数,保存校验和。
打印RDB文件:od -c dump.rdb
AOF持久化
AOF持久化时通过保存Redis服务器执行的写命令来记录数据状态,被写入AOF文件的所有命令都是以Redis命令请求协议。AOF持久化功能的实现可以分为命令追加(append)、文件写入、文件同步。
命令追加
当AOF持久化功能开启,服务器在执行一个命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾。
struct redisServer{
//AOF缓冲区
sds aof_buf;
}
文件写入与文件同步
Redis服务器进程实质上是一个事件循环,循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复,时间事件则负责定时运行函数。
服务器在处理文件事件时都可能会执行写命令,使得一些内容被追加到aof_buf缓冲区,每次服务器结束一个事件循环前,都会调用flushAppendOnlyFile函数,决定是否将缓冲区中的内容写入到文件。
appendfsync选项的值 | flushAppendOnlyFile函数 |
---|---|
always | 将aof_buf缓冲区中的所有内容写入并同步到AOF文件 |
everysec | 每隔一秒将缓冲区的内容写入AOF文件 |
no | 不将将aof_buf缓冲区的内容写入AOF文件 |
AOF文件载入和数据还原的时候,现在本地创建一个伪客户端,读取AOF文件中的命令,将命令用伪客户端执行,还原数据库状态。
AOF文件重写
AOF文件重写并不需要对已有的AOF进行读取,而是通过读取服务器当前的数据状态来实现。
AOF文件重写的时候,服务器会开辟一个新的重写缓冲区空间,当命令进入时,会将命令记录在AOF缓冲区和AOF重写缓冲区,当且仅当AOF的新文件生成后,向父进程发送信号,然后再将AOF重写缓冲区的内容录入AOF文件,原子性地将新的AOF文件替换旧的AOF文件。