RDB持久化

  RDB持久化功能可以将某个时间点内存中的Redis数据库状态保存到一个RDB文件中,这个文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态。RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行。

一、RDB文件的创建与载入
1. RDB文件的创建
  可以使用 SAVE 或 BGSAVE 命令来进行RDB文件的创建。
(1)SAVE:阻塞Redis服务器进程,直到RDB文件创建完成为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。
(2)BGSAVE:派生出一个子进程,由这个子进程负责创建RDB文件,服务器进程(父进程)可以继续处理命令请求。
2. RDB文件的载入
  RDB文件的载入工作是在服务器启动时自动执行的,Redis没有专门用于载入RDB文件的命令。服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成为止。
  由于AOF文件的更新频率通常比RDB文件的更新频率高,如果服务器开启了AOF持久化功能,服务器会优先使用AOF文件来还原数据库状态;只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据库状态。
3. BGSAVE命令执行时的服务器状态
(1)在BGSAVE命令执行期间,客户端发送的SAVE命令和BGSAVE命令都会被服务器拒绝,因为会产生竞争条件。
(2)如果BGSAVE命令正在执行,客户端发送的BGREWRITEAOF命令会被延迟到BGSAVE命令执行完成之后执行。
(3)如果BGREWRITEAOF命令正在执行,客户端发送的BGSAVE命令会被服务器拒绝。

 

二、自动间隔性保存
1. 设置保存条件
  通过设置Redis服务器配置的'save'选项,可以让服务器每隔一段时间自动执行一次BGSAVE命令;可以配置多个规则,只要满足其中一个规则就执行BGSAVE命令。'save'选项默认配置为:
save 900 1(在900秒之内,对数据库至少进行了一次修改,则执行BGSAVE命令)
save 300 10
save 60 10000
服务器程序会根据'save'选项设置服务器状态redisServer结构的'saveparams'属性:

'saveparams'属性是一个数组,数组中每个元素都是一个saveparam结构:

所以默认的保存条件数据结构如下:

 2. dirty计数器和lastsave属性

dirty计数器:记录距离上一次成功执行SAVE命令或BGSAVE命令之后,服务器对数据库状态进行了多少次修改。当服务器成功执行一个数据库修改命令之后,程序就会对dirty计数器进行更新,命令修改了多少次数据库,dirty计数器就会增加多少。
lastsave属性:是一个UNIX时间戳,记录了服务器上一次成功执行SAVE或BGSAVE命令的时间。
3. 检查保存条件是否满足
  Redis的服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查'save'选项所设置的保存条件是否已经满足,如果满足的话,就执行BGSAVE命令(遍历并检查saveparams数组中所有的保存条件,逐一与服务器状态的“dirty”属性和“lastsave”属性进行比较,只要有任意一个条件满足就执行BGSAVE命令)。

 

三、RDB文件结构
RDB文件整体结构如下:

(1)REDIS:5字节,用于在载入文件时判断文件是否为RDB文件。
(2)db_version:4字节,字符串表示的整数,记录了RDB文件的版本号。
(3)databases:长度不定,0或任意多个数据库,以及各个数据库中的键值对数据。
(4)EOF:1字节,标志着RDB文件正文内容结束。
(5)check_num:8字节,无符号整数,保存一个检验和,根据前面四部分内容进行计算得到,用于检查RDB文件是否有出错或损坏的情况出现。

1. databases部分
0号数据库和3号数据库非空的RDB文件结构示例:

其中每个非空数据库在RDB文件中的结构:

(1)SELECTDB:1字节,标志后面接着一个数据库号码。
(2)db_number:1、2、或5字节,保存一个数据库号码。
(3)key_value_pairs:长度不定,保存了数据库中所有的键值对数据,如果键值对带有过期时间,过期时间也会跟键值对保存在一起。
所以完整结构示例如下:

 

2. key_value_pairs部分
(1)不带过期时间的键值对结构:

TYPE:1字节,记录对象类型或底层编码,程序会根据这个常量的值来决定如何读入和解析value数据,值可以是以下常量其中一个。

key和value分别保存键值对的键对象和值对象。
(2)带过期时间的键值对结构:

EXPIRETIME_MS:1字节,标志后面接着一个以毫秒为单位的过期时间。
ms:8字节,带符号整数,记录一个以毫秒为单位的UNIX时间戳。

 

3. value的编码
(1)字符串对象
TYPE:REDIS_RDB_TYPE_STRING
编码:REDIS_ENCODING_INT或者REDIS_ENCODING_RAW
<1>编码为REDIS_ENCODING_INT的字符串对象结构:

其中'ENCODING'的值可以是REDIS_RDB_ENC_INT8、REDIS_RDB_ENC_INT16或者REDIS_RDB_ENC_INT32。
<2>编码为REDIS_ENCODING_RAW的字符串对象
若服务器开启了了RDB文件压缩功能,则:
字符串长度 <= 20字节,原样保存。
字符串长度 > 20字节,压缩保存。
若服务器关闭了RDB文件压缩功能,则RDB程序总是原样保存字符串值。
可以通过配置文件的'rdbcompression'选项来设置RDB文件压缩功能是否开启。
原样保存的字符串结构:

len保存字符串长度,string则保存字符串值。
压缩保存的字符串结构:

REDIS_RDB_ENC_LZF:标志着字符串已经被LZF算法压缩过了。
compressed_len:记录字符串压缩后的长度。
origin_len:记录字符串原来的长度。
compressed_string:记录压缩后的字符串。

(2)列表对象
TYPE:REDIS_RDB_TYPE_LIST
编码:REDIS_ENCODING_LINKEDLIST
结构示例:

list_length:记录了列表的长度,即当前列表保存了多少个项。
因为每一个列表项都是一个字符串对象,所以读入程序会以处理字符串对象的方式来保存和读入列表项。

(3)集合对象
TYPE:REDIS_RDB_TYPE_SET
编码:REDIS_ENCODING_HT
结构示例:

set_size:记录集合大小,即当前集合保存了多少个元素。
因为每一个集合元素都是一个字符串对象,所以读入程序会以处理字符串对象的方式来保存和读入集合元素。

(4)哈希表对象
TYPE:REDIS_RDB_TYPE_HASH
编码:REDIS_ENCODING_HT
结构示例:

hash_size:记录哈希表大小,即当前哈希表保存了多少个键值对。
因为键值对的键和值都是字符串对象,所以读入程序会以处理字符串对象的方式来保存和读入键值对。

(5)有序集合对象
TYPE:REDIS_RDB_TYPE_ZSET
编码:REDIS_ENCODING_SKIPLIST
结构示例:

sorted_set_size:记录了有序集合的大小,即当前有序集合保存了多少个元素。

(6)INTSET编码的集合
TYPE:REDIS_RDB_TYPE_SET_INTSET
保存时先将整数集合转换为字符串对象,然后再将这个字符串对象保存到RDB文件中;读取时则先读入字符串对象,再转换为整数集合对象。

(7)ZIPLIST编码的列表、哈希表或者有序集合
TYPE:REDIS_RDB_TYPE_LIST_ZIPLIST、REDIS_RDB_TYPE_HASH_ZIPLIST、REDIS_RDB_TYPE_ZSET_ZIPLIST
保存时先将压缩列表转换为一个字符串对象,再将这个字符串对象保存到RDB文件中;读取时则先读入字符串对象,再转换为压缩列表对象,最后根据TYPE的值,分别将压缩列表对象的类型设置为列表、哈希表或者有序集合。

 

原文地址:https://www.cnblogs.com/wujuntian/p/9249774.html