redis RDB(relation database)持久化

Redis RBD文件结构

+-------+-------------+-----------+-----------------+-----+-----------+
| REDIS | RDB-VERSION | SELECT-DB | KEY-VALUE-PAIRS | EOF | CHECK-SUM |
+-------+-------------+-----------+-----------------+-----+-----------+

                      |<-------- DB-DATA ---------->|

REDIS

  • 文件的最开头保存着 REDIS 五个字符,标识着一个 RDB 文件的开始。
  • 在读入文件的时候,程序可以通过检查一个文件的前五个字节,来快速地判断该文件是否有可能是 RDB 文件。

RDB-VERSION

  • 一个四字节长的以字符表示的整数,记录了该文件所使用的 RDB 版本号。

DB-DATA

  • 这个部分在一个 RDB 文件中会出现任意多次,每个 DB-DATA 部分保存着服务器上一个非空数据库的所有数据。

SELECT-DB

  • 这域保存着跟在后面的键值对所属的数据库号码。

  • 在读入 RDB 文件时,程序会根据这个域的值来切换数据库,确保数据被还原到正确的数据库上。

KEY-VALUE-PAIRS

  • 因为空的数据库不会被保存到 RDB 文件,所以这个部分至少会包含一个键值对的数据。

  • 每个键值对的数据使用以下结构来保存:

    ```c
    +----------------------+---------------+-----+-------+
    | OPTIONAL-EXPIRE-TIME | TYPE-OF-VALUE | KEY | VALUE |
    +----------------------+---------------+-----+-------+

     OPTIONAL-EXPIRE-TIME 域是可选的,如果键没有设置过期时间,那么这个域就不会出现; 反之,如果这个域出现的话,那么它记录着键的过期时间,在当前版本的 RDB 中,过期时间是一个以毫秒为单位的 UNIX 时间戳。

     KEY 域保存着键,格式和 REDIS_ENCODING_RAW 编码的字符串对象一样(见下文)。

     TYPE-OF-VALUE 域记录着 VALUE 域的值所使用的编码, 根据这个域的指示, 程序会使用不同的方式来保存和读取 VALUE 的值。

    ```

EOF

  • 标志着数据库内容的结尾(不是文件的结尾),值为 rdb.h/EDIS_RDB_OPCODE_EOF (255)。

CHECK-SUM

  • RDB 文件所有内容的校验和, 一个 uint_64t 类型值。
  • REDIS 在写入 RDB 文件时将校验和保存在 RDB 文件的末尾, 当读取时,根据它的值对内容进行校验。
  • 如果这个域的值为0,那么表示 Redis 关闭了校验和功能。

保存VALUE 的详细格式如下:

REDIS_ENCODING_INT 编码的 REDIS_STRING 类型对象:

  • 如果值可以表示为 8 位、 16 位或 32 位有符号整数,那么直接以整数类型的形式来保存它们:
```c
+---------+
| integer |
+---------+
```
  • 当读入这类值时,程序按指定的长度读入字节数据,然后将数据转换回整数类型。

  • 另一方面,如果值不能被表示为最高 32 位的有符号整数,那么说明这是一个 long long 类型的值,在 RDB 文件中,这种类型的值以字符序列的形式保存。

  • 一个字符序列由两部分组成:

```c
+-----+---------+
| LEN | CONTENT |
+-----+---------+

其中, CONTENT 域保存了字符内容,而 LEN 则保存了以字节为单位的字符长度。
```
  • 当进行载入时,读入器先读入 LEN ,创建一个长度等于 LEN 的字符串对象,然后再从文件中读取 LEN 字节数据,并将这些数据设置为字符串对象的值。

REDIS_ENCODING_RAW 编码的 REDIS_STRING 类型值有三种保存方式:

  • 如果值可以表示为 8 位、 16 位或 32 位长的有符号整数,那么用整数类型的形式来保存它们。

  • 如果字符串长度大于 20 ,并且服务器开启了 LZF 压缩功能 ,那么对字符串进行压缩,并保存压缩之后的数据。经过 LZF 压缩的字符串会被保存为以下结构:

```c
+----------+----------------+--------------------+
| LZF-FLAG | COMPRESSED-LEN | COMPRESSED-CONTENT |
+----------+----------------+--------------------+

LZF-FLAG 告知读入器,后面跟着的是被 LZF 算法压缩过的数据。
COMPRESSED-CONTENT 是被压缩后的数据, COMPRESSED-LEN 则是该数据的字节长度。
```
  • 在其他情况下,程序直接以普通字节序列的方式来保存字符串。比如说,对于一个长度为 20 字节的字符串,需要使用 20 字节的空间来保存它。这种字符串被保存为以下结构:
```c
+-----+---------+
| LEN | CONTENT |
+-----+---------+

LEN 为字符串的字节长度, CONTENT 为字符串。
```
  • 当进行载入时,读入器先检测字符串保存的方式,再根据不同的保存方式,用不同的方法取出内容,并将内容保存到新建的字符串对象当中。

REDIS_ENCODING_LINKEDLIST 编码的 REDIS_LIST 类型值保存为以下结构:

```c
+-----------+--------------+--------------+-----+--------------+
| NODE-SIZE | NODE-VALUE-1 | NODE-VALUE-2 | ... | NODE-VALUE-N |
+-----------+--------------+--------------+-----+--------------+

其中 NODE-SIZE 保存链表节点数量,后面跟着 NODE-SIZE 个节点值。节点值的保存方式和字符串的保存方式一样。
```
  • 当进行载入时,读入器读取节点的数量,创建一个新的链表,然后一直执行以下步骤,直到指定节点数量满足为止:
    • 读取字符串表示的节点值
    • 将包含节点值的新节点添加到链表中

REDIS_ENCODING_HT 编码的 REDIS_SET 类型值保存为以下结构:

```c
+----------+-----------+-----------+-----+-----------+
| SET-SIZE | ELEMENT-1 | ELEMENT-2 | ... | ELEMENT-N |
+----------+-----------+-----------+-----+-----------+

SET-SIZE 记录了集合元素的数量,后面跟着多个元素值。元素值的保存方式和字符串的保存方式一样。
```
  • 载入时,读入器先读入集合元素的数量 SET-SIZE ,再连续读入 SET-SIZE 个字符串,并将这些字符串作为新元素添加至新创建的集合。

REDIS_ENCODING_SKIPLIST 编码的 REDIS_ZSET 类型值保存为以下结构:

```c
+--------------+-------+---------+-------+---------+-----+-------+---------+
| ELEMENT-SIZE | MEB-1 | SCORE-1 | MEB-2 | SCORE-2 | ... | MEB-N | SCORE-N |
+--------------+-------+---------+-------+---------+-----+-------+---------+
其中 ELEMENT-SIZE 为有序集元素的数量, MEB-i 为第 i 个有序集元素的成员, SCORE-i 为第 i 个有序集元素的分值。
```
  • 当进行载入时,读入器读取有序集元素数量,创建一个新的有序集,然后一直执行以下步骤,直到指定元素数量满足为止:
    • 读入字符串形式保存的成员 member
    • 读入字符串形式保存的分值 score ,并将它转换为浮点数
    • 添加 member 为成员、 score 为分值的新元素到有序集

REDIS_ENCODING_HT 编码的 REDIS_HASH 类型值保存为以下结构:

```c
+-----------+-------+---------+-------+---------+-----+-------+---------+
| HASH-SIZE | KEY-1 | VALUE-1 | KEY-2 | VALUE-2 | ... | KEY-N | VALUE-N |
+-----------+-------+---------+-------+---------+-----+-------+---------+
HASH-SIZE 是哈希表包含的键值对的数量, KEY-i 和 VALUE-i 分别是哈希表的键和值。
```
  • 载入时,程序先创建一个新的哈希表,然后读入 HASH-SIZE ,再执行以下步骤 HASH-SIZE 次:
    • 读入一个字符串
    • 再读入另一个字符串
    • 将第一个读入的字符串作为键,第二个读入的字符串作为值,插入到新建立的哈希中。

REDIS_LIST 类型、 REDIS_HASH 类型和 REDIS_ZSET 类型都使用了 REDIS_ENCODING_ZIPLIST 编码, ziplist 在 RDB 中的保存方式如下:

```c
+-----+---------+
| LEN | ZIPLIST |
+-----+---------+
```
  • 载入时,读入器先读入 ziplist 的字节长,再根据该字节长读入数据,最后将数据还原成一个 ziplist 。

REDIS_ENCODING_INTSET 编码的 REDIS_SET 类型值保存为以下结构:

```c
+-----+--------+
| LEN | INTSET |
+-----+--------+
```
  • 载入时,读入器先读入 intset 的字节长度,再根据长度读入数据,最后将数据还原成 intset 。

reference

powered by Gitbook该文件修订时间: 2019-07-05 09:33:43

results matching ""

    No results matching ""