redis-RDB写入

66 阅读4分钟

一、背景

redis是一个内存数据库,把数据库的状态放在内存里面,但是如果服务器退出,那么内存的数据就会被清空。 因此,redis提供了RDB持久化,把数据保存在磁盘里面,防止数据的丢失。

注意:数据恢复的时候,如果开启了AOF持久化,那么会优先使用AOF来还原数据

二、文件的创建

保存 RDB 文件的方法:SAVE 以及 BGSAVE

区别:

  • SAVE 会阻塞服务器的进程,新的操作请求会被操作系统内核的网络缓冲区缓存起来,它们的执行会被延迟,直到 SAVE 操作完成,Redis 主线程恢复工作。
  • BGSAVE 会创建一个子进程,创建RDB文件,当完成以后向父进程发送信号。父进程则继续处理命令请求,并通过轮询方式等待子进程的信号

Q:那么BGSAVE开启了一个子进程进行数据保存的工作,那么如果我尝试再次执行SAVA,BGSAVE会怎么样?

A:会被拒绝,服务器不允许父子进程,或者多个进程对文件进行操作(出于性能考虑以及防止竞态条件的产生)

三、自动保存

save time cnt:服务器在time秒以内,对数据库进行了至少cnt次修改,那么就会执行BGSAVE命令。比如 save 300 10:服务器在300s以内,对数据库进行了至少10次的修改。

可以设置多个保存条件,只要有一个生效就行,因此其底层是保存这些状态用的是一个数组,那么redis通过遍历整个数组来判断是否会出现问题。

redis里面有一个结构体:

struct redisServer{
    //...
    // 记录当前修改的次数
    int dirty;
    // 记录上次执行保存的时间
    time_t lastsave;

    // 记录定时保存的参数(数组结构)
    struct saveparam* saveparams;
    
    //...
}


struct saveparam{
    time_t seconds;
    int changes
}

保存完成以后,修改dirty以及lastsave的内容

Q:那么保存状态是什么样的?比如我save 900 1:900s以内修改一次数据就保存?那岂不是每次操作都保存一次?

A:对时间的判断是 time_now() - lastsave>900 && dirty>=1才会保存,也就是超过900s才行。

四、RDB文件结构

image.png

  • REDIS:就是REDIS这五个字符,表示这是一个REDIS文件。
  • db_version:记录当前的RDB的版本,会向后兼容。
  • database:记录整个数据库(可以有多个数据库)的kv数据
  • EOF:一个字节,标志着内容的结束
  • check_sum:是一个校验和,对前面四个数据段的校验(八字节)

4.1 database 部分

image.png

SELECTDB是一字节,标识着下一个数据是数据库号码。读取到数据库号码以后,就会调用SELECT命令,根据读入的数据库号码进行切换。

key_value_pairs:保存了数据库中所有键值对的数据,如果其有过期时间,那么过期时间也会随着一起进行保存。

4.2 kV部分

不带过期时间的KV

image.png

带有过期时间的KV

image.png

  • TYPE记录的是value的类型(一字节标识),其key一直都是string对象。
  • EXPIRETIME_MS:也是一个标识(1字节),标识下一个读入的是过期时间。
  • ms:一个8字节长的有符号整数,UNIX时间戳

4.3 value的编码

1. 字符串

字符串对象涉及到两个:存的是整型数据以及真字符串

  1. 如果存的是整数、

    那么其value里面会有一个字节进行标识,比如这个标记字节的高2位通常是 11,后6位指示具体是 INT8INT16 还是 INT32

  2. 如果存的是字符串

    • 如果是LZF 压缩的字符串,那么其结构如下:
      • image.png
      • 它的高2位是 11,后6位指示这是 LZF 压缩。
    • 如果是普通的字符串,那么:
      • image.png
      • 如果第一个字节的头2位是 00,则长度在后6位 (长度 0-63)。
      • 如果第一个字节的头2位是 01,则长度在后6位 + 下一个字节 (长度 64-16383)。
      • 如果第一个字节的头2位是 10,则长度在接下来的4个字节 (长度可达 2^32−1)。

2. 集合类型

Redis 中的集合类型,如列表 (List)、集合 (Set)、哈希 (Hash) 和有序集合 (Sorted Set),在 RDB 文件中存储时,其结构具有相似的模式:首先记录集合内元素的数量,然后依次存储各个元素。

通用结构模式:

+--------------------------+-----------------+-----------------+-----+-----------------+
| 元素数量 (Collection Size) | 第一个元素 (Item1) | 第二个元素 (Item2) | ... | 第 N 个元素 (ItemN) |
+--------------------------+-----------------+-----------------+-----+-----------------+

以哈希为例,里面的数据格式为:

Hash_Value_RDB: +-------------+----------------+---------------+----------------+-----------------+-------------------+-----------------+ 
| 元素数量(2) | "name"长度(4) | "name"数据 | "redis"长度(5) | "redis"数据 | "version"长度(7) | "version"数据 | ... (接"7")
| (1 byte) | (1 byte, 0x04) | 'n''a''m''e' | (1 byte, 0x05) | 'r''e''d''i''s' | (1 byte, 0x07) | 'v''e''r''s'...' | 
+-------------+----------------+---------------+----------------+-----------------+-------------------+-----------------+