Redis设计与实现 笔记 第十章RDB持久化

RDB 持久化

Redis 是一个键值对数据库服务器,是在内存中存储的,当发生崩溃时,存储的数据将会丢失,所以需要一个落地策略.
在此基础上, Redis 提供了 RDB 持久化功能, 这个功能可以将 Redis 在内存中的数据库状态保存到磁盘里面,避免数据意外丢失.
RDB 持久化功能所生成的 RDB 文件是一个通过压缩的二进制文件,通过改文件可以还原成 RDB 文件生成时的数据库状态.

SAVE 命令 和 BGSAVE 命令提供了 RDB 持久化的两种方式.

SAVE是当前进程进行持久化, BGSAVE 命令提供了子进程的持久化方式.

10.1 RDB 文件的创建与载入

SAVE 命令会阻塞 Redis 服务器进程, 直到 RDB 文件创建完毕为止,在服务器阻塞期间,将不能处理任何请求.

和 SAVE 不同, BGSAVE 会创建一个子进程,专门进行 RDB 文件创建.

和使用 SAVE 命令或者 BGSAVE 命令创建 RDB 文件不同, RDB 文件的载入工作是服务器启动时候自动执行的, 所以 Redis 并没有专门用来调用 RDB 的启动命令,简单粗暴的检查当前文件夹下是否有对应的 RDB 文件,来进行是否载入 RDB 的存储设置
还有一个注意点
AOF 问价你的更新频率通常比 RDB 文件的更新频率高,所以
所以如果开启了 AOF 持久化功能, 那么服务器会有限使用 AOF 文件来还原数据.
也就是只有当 AOF 持久化关闭之后,才能使用 RDB 持久化

10.1.1 SAVE 命令执行时的服务器状态

当 SAVE 命令执行时, Redis 服务器会被阻塞,所以当 SAVE 命令正在执行时,客户端发送的所有命令请求都会被阻塞,只有在服务器执行完 SAVE 命令,重新开始接受命令请求之后,客户端发送的命令才会被处理.

10.1.2 BGSAVE 命令执行时的服务器状态

在 BGSAVE 命令, 在 BGSAVE 命令执行期间, 服务器在应对 SAVE, BGSAVE , BGREWRITEAOF 三个名的方式会有不同.

在 BGSAVE 命令执行期间, SAVE 命令将会被服务器拒绝, 这也是当然,多个进程同时进行持久化,难免会有一些条件竞态,所以 当在 BGSAVE 命令执行期间, 发护短发送的 BGSAVE 命令会被服务器拒绝.理由同上.

BGREWRITEAOF 和 BGSAVE 两个命令不能同时执行:

如果 BGSAVE 命令正在执行, BGREWRITEAOF 命令不会直接被拒绝,将在 BGSAVE 完成之后再继续执行.

如果 BGREWRITEAOF 命令正在执行,那么 BGSAVE 命令将直接拒绝

10.1.3 RDB 文件载入时的服务器状态

服务器在载入 RDB 文件期间, 会一直处于阻塞状态,直到完成

10.2 自动间隔性保存

与 SAVE 不同, BGSAVE 是另开一个子进程进行保存的, 所以可以使用自动保存策略来进行存储的,如下

save 900 1
save 300 10
save 60 10000

意思为:
1): 当过去的900秒内进行了1次存储进行,那就进行存盘.
2): 当过去的300秒内进行了10次存储进行,那就进行存盘.
3): 当过去的60秒内进行了10000次存储进行,那就进行存盘.

10.2.1 设置保存条件
// 服务器的保存条件(BGSAVE 自动执行的条件)
struct saveparam {

    // 多少秒之内
    time_t seconds;

    // 发生多少次修改
    int changes;

};
struct saveparam *saveparams;   /* Save points array for RDB */

带入上述的配置
就是修改 savepram 相应的值完成配置.

10.2.2 dirty 计数器和 lastsave 属性

除了 saveparams 数组之外,服务器状态还维持一个 dirty 计数器和一个 lastsave 属性.

struct redisServer {
  
  //修改 计数器
  long long dirty;
  
  //最后一次保存时间
  time_t lastsave;
    
};

每当进行修改之后, dirty 计数器就+1.
每当进行 BGSAVE 之后, lastsave 就设置为当前时间戳.

10.2.3 检查保存条件是否满足

在周期性函数中 serverCron() 中,就会在每次循环进行一个条件检查.
拿 redisServer.dirty 和 redisServer.lastsave 跟 saveparam 数组进行比较.
当条件满足的时,就进行 BGSAVE 命令.

10.3 RDB 文件结构
REDISdb_versiondatabasesEOFcheck_sum

文件的开头是 REDIS 五个字符.

db_version 是当前 REDIS 的版本.

databases 部分包含着 零个或任意多个数据库,以及各个数据库中的键值对数据.

EOF 表示当前 databases 结束.

check_sum 表示当前 RDB 文件的校验和.

10.3.1 databases 部分
REDISdb_versiondatabase 0database 3EOFcheck_sum

这是一个带有两个数据库的 RDB 文件结构 ,
紧接着介绍的是 database 结构构成

SELECTDBdb_numberkey_value_pairs

SELECTDB 是一个字符,表示下面将读取 databases 内容

db_number 保存的是当前数据库的号码,即 SELECT 切换的命令带的字符

key_value_pairs 部分保存了数据库所有键值对,为一个动态的数据结构,根据 数量, 类型, 内容以及是否有过期时间等不同, 进行动态的变化.

10.3.2 key_value_pairs 部分

此章和后续几张的内容,像极了网络中的序列化以及反序列化思路,也许本就是相同的概念,序列化和反序列化是相反的一个函数,一个负责从对象中将属性解析成文件,一个负责从文件中将属性解析成对象.不同的序列化和反序列化,可能其流程不同,但是结果和目的就是,相同的输入必须输出成相同的输出.

下面进行简单的介绍:

TYPEkeyvalue

TYPE 为1个字节 可以是以下常量中的一个

REDIS_RDB_TYPE_STRING
REDIS_RDB_TYPE_LIST
REDIS_RDB_TYPE_SET
REDIS_RDB_TYPE_ZSET
REDIS_RDB_TYPE_HASH
REDIS_RDB_TYPE_LIST_ZIPLIST
REDIS_RDB_TYPE_SET_ZIPLIST
REDIS_RDB_TYPE_ZSET_ZIPLIST
REDIS_RDB_TYPE_HASH_ZIPLIST

key 和 REDIS_RDB_TYPE_STRING 的 value 一个类型,根据内容长度不同,key 的长度也不相同

value 就不用在这先提,后续会详细说明

再一个是带有过期时间 key_value_pairs 结构

EXPIRETIME_MSmsTypekeyvalue

和无过期时间版本大致相同,多了2个前缀字节,作用也一目了然.

EXPIRETIME_MS 表示当前是带有过期时间的 key_value_pairs

ms 为过期时间

10.3.3 value 的编码
字符串对象

字符串的保存规则,对象的 encode 需要是 REDIS_ENCODING_INT 或者是 REDIS_ENCODING_RAW (REDIS_ENCODING_EMBSTR呢?).
保存的结构如下:

ENCODINGinteger

当字符串对象结构是 REDIS_ENCODING_RAW 时, 将以REDIS_RDB_TYPE_STRING 形式进行存储,且有特殊的规则:
如果字符串的长度小于20字节时,这个字符串会被原样保存.
如果字符串的长度大于20字节时,这个字符串将会被压缩之后再保存.

上述条件是假设服务器打开了 RDB 文件压缩功能的情况下进行的.
压缩完毕的结果如下

REDIS_RDB_ENC_LZFcompressed_lenorigin_lencompressed_string

一个正常的字符串结构

5“hello”

一个经过压缩的字符串结构

REDIS_RDB_ENC_LZF621“?aa???”
列表对象

TYPE 值为 REDIS_RDB_TYPE_LIST
整体结构:

list_lengthitem1item2itemN

item结构:

lenstr

举例包含3个元素的列表对象:

35“hello”5“world”1“1”

list_length 记录当前列表对象长度, len记录当前元素的长度,str为具体内容

集合对象

TYPE 值为 REDIS_RDB_TYPE_SET
集合对象从结构上来说和列表对象相同,实际上存储方式也是类似

整体结构:

set_sizeitem1item2itemN

item结构:

lenstr

举例包含3个元素的列表对象:

35“hello”5“world”1“1”
哈希表对象

TYPE 值为 REDIS_RDB_TYPE_HASH
哈希对象从结构上来说和列表对象相同,实际上存储方式也是类似

整体结构:

hash_sizeitem1item2itemN

item结构:

lenstr

举例包含3个元素的列表对象:

35“hello”5“world”1“1”
有序集合对象

TYPE 值为 REDIS_RDB_TYPE_ZSET
哈希对象从结构上来说和列表对象相同,实际上存储方式也是类似

整体结构:

hash_sizeitem1item2itemN

item结构:
len|str|len|score
—|---

举例包含3个元素的列表对象:

22“pi”3.144“3.14”1“e”3“2.7”
INTSET 编码的集合

TYPE 值为 REDIS_RDB_TYPE_SET_INTSET, 那么 value 保存的就是一个整数集合对象, RDB 文件保存这种对象的方法是, 将整数集合转换成字符串对象,再进行保存, 从 RDB 中读取的时候,将字符串转成整数集合对象,进行恢复操作.

ZIPLIST 编码的列表,哈希表,或者有序集合

TYPE 值为
REDIS_RDB_TYPE_LIST_ZIPLIST
REDIS_RDB_TYPE_SET_ZIPLIST
REDIS_RDB_TYPE_ZSET_ZIPLIST
REDIS_RDB_TYPE_HASH_ZIPLIST
存入:
1): 将压缩列表转换成一个字符串对象
2): 将转换所得的字符串对象保存到 RDB 文件
读取:
1): 将字符串转换成压缩列表
2): 根据 TYPE 进行分类生成,然后进行存放

总结

本章介绍了 RDB 的工作模式,通过 SAVE BGSAVE 可以进行 RDB 持久化,可以进行持久化策略配置,在 serverCron 周期性函数调用时,满足策略后进行持久化调用.
RDB 对不同的对象编码有不同的持久化策略,类似于序列化和反序列化的思维,进行文件的编写存储

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值