RDB持久化机制

Redis的RDB持久化通过创建RDB文件保存数据库状态,避免数据丢失。RDB文件由rdbSave函数创建,SAVE命令会阻塞服务器,而BGSAVE命令通过子进程执行。服务器根据save配置定期执行BGSAVE,通过dirty计数器和lastsave属性检查条件。RDB文件结构包括REDIS标识、版本号、数据库数据和校验和,便于加载和验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RDB文件保存数据库状态

服务器中的非空数据库及其键值对,统称为数据库状态。Redis的RDB持久化,将数据库状态保存到磁盘,避免内存数据掉电易失。
RDB持久化既可以手动执行,也可以通过配置定期执行。它会将某个时间点的数据库状态保存到一个RDB文件(压缩的二进制文件)中,以便后期方便借此还原数据库状态。

1. RDB文件的创建和载入

RDB文件的创建由rdbSave函数负责,SAVE命令和BGSAVE命令会以不同的形式调用该函数:

  • SAVE命令会阻塞进程,直到RDB文件创建完毕。在此期间,服务器不会响应任何命令请求
  • BGSAVE命令会fork一个子进程出来,由子进程负责生成RDB文件,父进程依旧继续处理命令请求

和RDB创建不同的是,RDB文件的载入并没有专门的函数、命令,只要Redis服务器启动时检测到RDB文件存在,就会自动将其载入(开启AOF,优先使用AOF;关闭AOF,使用RDB)。在RDB载入期间,服务器会一直处于阻塞状态,直至RDB载入完毕!

虽说在BGSAVE命令执行期间,服务器主进程会正常响应命令请求,但是对3个命令除外:

  • SAVE命令:BGSAVE命令执行期间,服务器会拒绝SAVE命令。服务器禁止SAVE/BGSAVE命令同时执行,是为了避免父进程、子进程同时执行rdbSave函数(防止产生竞争条件)
  • BGSAVE命令:BGSAVE命令执行期间,服务器会拒绝BGSAVE命令。同时执行两个BGSAVE命令也会产生竞争条件
  • BGREWRITEAOF命令:
    • ①如果BGSAVE命令正在执行,BGREWRITEAOF命令会被排到BGSAVE命令执行完毕后执行
    • ②如果BGREWRITEAOF命令正在执行,服务器会拒绝BGSAVE命令(都会fork子进程执行大量磁盘写入操作,性能考虑)

2.间隔执行BGSAVE命令

SAVE命令会阻塞服务器主进程,BGSAVE命令不会阻塞主进程(fork子进程执行RDB生成),所以Redis允许通过配置,让服务器间歇性的执行BGSAVE命令。
服务器提供以下配置:

# 服务器在X秒内,对数据库至少修改了Y次,就会触发BGSAVE命令的执行
save 900 1
save 300 10
save 60 10000

2.1 saveparam数组

服务器会根据上述save配置的条件,将其设置到服务器状态redisServer的saveparam数组中,数组的每个元素都是一个saveparam结构,包含秒数和修改次数:

struct saveparam *saveparams;


// 服务器的保存条件(BGSAVE 自动执行的条件)
struct saveparam {
    // 多少秒之内
    time_t seconds;
    // 发生多少次修改
    int changes;
};

在这里插入图片描述

2.2 dirty计数器和lastsave属性

  • dirty计数器记录了上一次成功执行SAVE或BGSAVE命令后,服务器对服务器状态进行了多少次的修改(增删改)
  • lastsave记录了上一次成功执行SAVE或BGSAVE命令的时间戳
    在这里插入图片描述

2.3周期性检查save配置是否满足

服务器周期性操作函数serverCron(维护正在运行的服务器,职责之一就是检查save是否满足)默认每隔100ms就会执行一次:遍历saveparam数组中的所有元素,只要任意一条设置满足(次数、时间都符合),就会触发BGSAVE命令的执行。

BGSAVE命令执行完毕后,dirty计数器会被重置为0,lastsave保存的时间戳会被更新!

3.RDB文件结构

  • REDIS:占5个字节的5个字符,可在服务器载入RDB时快速检查是否为RDB文件
  • db_version:4字节的字符串表示的整数,表示RDB文件的版本号
  • databases:零个或任意个数据库,及其内部的键值对数据
  • EOF:占1字节,表示RDB文件正文部分已经结束
  • check_sum:占8字节的无符号整数,对以上4部分计算出的校验和。载入RDB文件时程序会计算校验和,并与check_sum内的校验和比对,检查RDB文件是否损坏

假设0号、3号数据库非空
在这里插入图片描述

非空数据库的结构如下:

  • SELECTDB:1字节的常量,表示下一个为数据库号码
  • db_number:数据库号码(号码不同,1/2/5字节),程序读到此处,会调用SELECT命令,切换数据库
  • key_value_pairs:保存了所有的键值对数据(过期键值对数据也在此处)
    在这里插入图片描述
    对于保存键值对数据的key_value_pairs部分结构:
  • EXPIRETIME_MS:占1字节,告诉程序接下来要读的是以ms为单位的过期时间
  • ms:8字节,以ms为单位的过期时间
  • TYPE:value的类型,占1字节
  • key:字符串对象
  • value:任意类型的Redis对象
    在这里插入图片描述
    TYPE记录了value的类型,程序会根据TYPE的值解析value:

① TYPE值为REDIS_RDB_TYPE_STRING,保存的是字符串对象

字符串对象的编码可以是:

  • REDIS_ENCODING_INT(值为REDIS_RDB_ENC_INT8、REDIS_RDB_ENC_INT16、REDIS_RDB_ENC_INT32,表示RDB文件使用8/16/32位来保存整数)
  • REDIS_ENCODING_RAW:保存的字符串(长度>20字节会被LZF算法压缩)

未压缩的字符串会以如下结构保存:
在这里插入图片描述
经过LZF压缩的字符串以以下结构保存(第1个是LZF标记,根据后3个解压):
在这里插入图片描述
② TYPE值为REDIS_RDB_TYPE_LIST,保存的是列表对象
列表长度 + 列表项
在这里插入图片描述
③ TYPE值为REDIS_RDB_TYPE_SET,保存的是集合对象
在这里插入图片描述
④ TYPE值为REDIS_RDB_TYPE_HASH,保存的是哈希表对象
在这里插入图片描述
⑤ TYPE值为REDIS_RDB_TYPE_ZSET,保存的是有序集合对象
在这里插入图片描述
⑥ TYPE值为REDIS_RDB_TYPE_SET_INTSET,保存的是整数集合对象
保存该对象的方式:先将整数集合转换为字符串对象,然后再保存到RDB文件中。

⑦ TYPE值为REDIS_RDB_TYPE_LIST_ZIPLIST、REDIS_RDB_TYPE_HASH_ZIPLIST、REDIS_RDB_TYPE_ZSET_ZIPLIST,保存的是压缩列表对象
将压缩列表对象转换为 字符串对象后,存储到RDB文件中。读RDB时会先将其转换为压缩列表后,再根据TYPE的值,转换为列表、哈希表、有序集合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值