RDB 文件的创建与载入
一个概念:服务器中非空数据库以及数据库中的键值对 称为 数据库状态
创建
def SAVE():
# 创建RDB文件
rdbSave()
def BGSAVE():
# 创建子进程
pid = fork()
if pid == 0:
# 子进程负责创建RDB文件
rdbSave()
# 完成之后向父进程发送信号
signal_parent()
else if pid > 0:
# 父进程继续处理命令请求,并通过轮询等待子进程的信
handle_request_and_wait_signal()
else:
# 处理出错情况
handle_fork_error()
- SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求
- BGSAVE命令会派生出一个子进程(与主进程具有相同(共享)内存内容的进程),然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求;
- BGSAVE命令执行时的服务器状态
- BGSAVE执行期间,客户端发送的SAVE、BGSAVE 会被服务器拒绝,避免rdbSave()重复调用
- BGSAVE正在执行,客户端发送的BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行;BGREWRITEAOF正在执行,客户端发送的BGSAVE命令会被服务器拒绝。原因是性能考虑,这两个操作并发出两个子线程,并且都进行了大量磁盘写入操作
载入
服务器载入RDB文件会一直处于阻塞状态
自动间歇性保存
-
当服务器启动的时候,客户端可以设置服务器的save选项,每隔一段时间执行一次BGSAVE(serverCron());
/** * 客户端没有配置->默认的配置 * 任意条件满足即合 */ save 900 1 //900秒内,对数据库至少一次修改 save 300 10 save 60 10000
- 设置保存条件
-
结构
struct redisServer { // ... // 记录了保存条件的数组 struct saveparam *saveparams; // 修改计数器 long long dirty; // 上一次执行保存的时间 time_t lastsave; // ... }; struct saveparam { // 秒数 time_t seconds; // 修改数 int changes; };
- 根据配置来设置redisServer中的saveparams
- dirty计数器:记录上一次SAVE或BGSAVE后,数据库状态进行了多少次修改1
- lastsave是UNIX时间戳,上一次SAVE或BGSAVE时间
-
- 检查保存条件是否满足
-
伪代码
def serverCron(): # ... # 遍历所有保存条件 for saveparam in server.saveparams: # 计算距离上次执行保存操作有多少秒 save_interval = unixtime_now()-server.lastsave # 如果数据库状态的修改次数超过条件所设置的次数 # 并且距离上次保存的时间超过条件所设置的时间 # 那么执行保存操作 if server.dirty >= saveparam.changes and save_interval > saveparam.seconds: BGSAVE() # ...
- 服务器周期性函数serverCorn默认每100mm执行一次,其中一项工作就是检查BGSAVE命令的条件是否满足
- 任意saveparam满足,就执行BGSAVE
-
RDB文件结构
REDIS | db_version | databases | EOF | check_sum |
---|---|---|---|---|
“REDIS” | “0006” | EOF | 6265312314761917404 |
- REDIS长度5字节,保存REDIS五个字符。快速检查载入文件是否是RDB文件;
- db_version 长度为4,0006代表第6个版本;
- databases,0或多个数据库,以及数据库中的键值对;数据库状态为空,这部分为空0字节。
- EOF常量长度1字节。读到这里标志RDB文件正文结束,所有数据库键值对加载完毕;
- chack_sum是8字节长无符号整数,记录前四项的校验和。
databases部分
带有两个数据库的RDB文件:
databases结构:
- SELECTDB 常量,标志即将要读入的数据库号db_number
- db_number 数据库号,长度1、2、5字节;读取数据库号后,后面的键值对就能正确写入到不同的库中;
- key_value_pairs 数据库键值对数据,带过期时间;
key_value_pairs
EXPIRSTIME_MS | Ms | TYPE | key | value |
---|---|---|---|---|
EXPIRSTIME_MS | 1515513600000 | REDIS_RDB_TYPE_STRING | Key | value |
-
如果向一个集合键增加三个新元素,dirty会加3 ↩