rdb:将数据库的快照以二进制格式保存在文件中,redis重启后直接加载数据。可以通过save和bgsave命令生成rdb。当然我们可以在生成rdb文件时指定规则,例如
save 60 1000
如果60秒内不少于1000个key发生了改动,则生成一个新的rdb文件。
- RDB定时逻辑
- 若当前程序存在子进程,则检查是否有子进程已执行完成,如果有,则执行对应的父进程进行收尾工作
- 检查服务器自从上一次生成RDB后,redis服务器变更了多少个健,若满足以下条件则开始生成RDB文件:
- 满足设定的RDB生成配置
- 上一次RDB成功生成已过去CONFIG_BGSAVE_RETRY_DELAY(5秒)
- RDB持久化进程
-
fork子进程(bgsave命令创建子进程,save命令则是调用主进程,因此会造成阻塞)
子进程会“复制”父进程的用户空间作为自己的用户空间,所以子进程和父进程都有自己独立的进程空间(同时会共享部分数据)。fork函数调用一次,会分别在父进程和子进程两处返回。
- 创建RDB进程
- 尽可能将RDB进程绑定到用户配置的CPU列表bgsave_cpulist上,减少不必要的进程切换,最大程度提高性能。
- 生成RDB文件
- 打开一个临时文件用于保存数据
- 初始化负责读/写文件的函数
- 赋值fsync
- 将redis数据库的内容写到临时文件中
- 重新命名临时文件,替换旧的RDB文件
- 更新server相关的RDB属性
- 写入RDB数据
- 往文件中写入一个RDB标志,标志该文件是RDB文件
- 写入辅助字段,如版本号、创建时间……
- 将数据字典以外的数据保存到RDB中
- 遍历所有的数据库
- 写入RDB_OPCODE_SELECTDB标志和数据库ID
- 写入RDB_OPCODE_RESIZEDB标志和数据库字典大小、过期字典大小
- 遍历数据库的键值对,将键值对和过期时间写入RDB中
- 若是过期时间则写入过期标志和过期时间戳
- 若是LRU或LFU则记录空闲时间或LFU计数
- 写入键值对标志,再写健内容再写值内容
- 将redis中的lua脚本写入RDB文件
- 写入结束标志
- 写入校验码
- 退出RDB进程
- 更新server的运行时数据
-
父进程收尾
- 检查是否存在已结束的子进程
- 获取子进程的结束代码和中断信号,根据这些标志做不同的逻辑处理
- 如果子进程是RDB进程,RDB数据保存成功后,需将RDB文件发送给正在同步的从服务器
-
RDB文件加载过程
- 读取RDB文件里的RDB标志
- 分析RDB文件。首先读取字节码,再根据标志字节进行相应的处理。
- 读取键值对,转换为redisObject
- 如果读取到健已过期,且当前服务器是主节点,则删除该健
- 将读取的键值对加入数据字典中
- 若redis版本大于5还需检查校验码
-