详解Redis持久化(2)

39 阅读7分钟

2.3RDB文件结构

RDB 持久化文件 dump.rdb 整体上有五部分构成:

图片.png (1)SOF

SOF是一个常量一个字符串REDIS,仅包含这五个字符,其长度为5。用于标识RDB文件的开始,以便在加载RDB文件时可以迅速判断出文件是否是RDB文件。

(2)rdb_version

这是一个整数,长度为4字节,表示RDB文件的版本号。

(3)EOF

EOF是一个常量,占用一个字节,用于标识RDB数据的结束,校验和的开始。

(4)check_sum

校验和check_sum用于判断RDB文件中的内容是否出现数据异常。其采用的是CRC校 验算法。

CRC 校验算法:

在持久化时,先将SOF、rdb_version 及内存数据库中的数据快照这三者的二进制数据拼 接起来,形成一个二进制数(假设称为数 a),然后再使用这个a除以校验和check_sum,此 时可获取到一个余数b,然后再将这个b拼接到a的后面,形成databases。

在加载时,需要先使用check_sum 对 RDB 文件进行数据损坏验证。验证过程:只需将RDB文件中除EOF与check_sum 外的数据除以check_sum。只要除得的余数不是0,就说明文件发生损坏。当然,如果余数是0,也不能肯定文件没有损坏。

这种验证算法,是数据损坏校验,而不是数据没有损坏的校验。

(5)databases

图片.png databases 部分是 RDB 文件中最重要的数据部分,其可以包含任意多个非空数据库。而 每个 database 又是由三部分构成:

  • SODB:是一个常量,占 1 个字节,用于标识一个数据库的开始。
  • db_number:数据库编号。
  • key_value_pairs:当前数据库中的键值对数据。

图片.png

每个key_value_pairs又由很多个用于描述键值对的数据构成

  • VALUE_TYPE:是一个常量,占1个字节,用于标识该键值对中value的类型。
  • EXPIRETIME_UNIT:是一个常量,占1个字节,用于标识过期时间的单位是秒还是毫秒。
  • time:当前key-value的过期时间。

2.4RDB持久化过程

图片.png 对于Redis默认的 RDB 持久化,在进行bgsave持久化时,redis-server进程会fork出一 个bgsave子进程,由该子进程以异步方式负责完成持久化。而在持久化过程中,redis-server 进程不会阻塞,其会继续接收并处理用户的读写请求。

bgsave子进程的详细工作原理如下:

由于子进程可以继承父进程的所有资源,且父进程不能拒绝子进程的继承权。所以,bgsave子进程有权读取到redis-server进程写入到内存中的用户数据,使得将内存数据持久 化到 dump.rdb 成为可能。

bgsave子进程在持久化时首先会将内存中的全量数据copy到磁盘中的一个RDB临时文 件,copy结束后,再将该文件rename为dump.rdb,替换掉原来的同名文件。

图片.png 不过,在进行持久化过程中,如果redis-server进程接收到了用户写请求,则系统会将内存中发生数据修改的物理块copy出一个副本。等内存中的全量数据copy结束后,会再将副本中的数据copy到RDB临时文件。这个副本的生成是由于Linux系统的写时复制技术(Copy-On-Write)实现的。

写时复制技术是Linux系统的一种进程管理技术。

原本在Unix系统中,当一个主进程通过fork()系统调用创建子进程后,内核进程会复制主进程的整个内存空间中的数据,然后分配给子进程。这种方式存在的问题有以下几点:

  • 这个过程非常耗时
  • 这个过程降低了系统性能
  • 如果主进程修改了其内存数据,子进程副本中的数据是没有修改的。即出现了数据冗余,而冗余数据最大的问题是数据一致性无法保证。

现代的Linux则采用了更为有效的方式:写时复制。子进程会继承父进程的所有资源,其中就包括主进程的内存空间。即子进程与父进程共享内存。只要内存被共享,那么该内存就是只读的(写保护的)。而写时复制则是在任何一方需要写入数据到共享内存时都会出现异常,此时内核进程就会将需要写入的数据copy出一个副本写入到另外一块非共享内存区域。

3.AOF持久化

AOF,Append Only File,是指 Redis 将每一次的写操作都以日志的形式记录到一个 AOF文件中的持久化技术。当需要恢复内存数据时,将这些写操作重新执行一次,便会恢复到之前的内存数据状态。

3.1AOF基础配置

(1)AOF的开启

图片.png

默认情况下AOF持久化是没有开启的,通过修改配置文件中的appendonly属性为yes可以开启。

(2)文件名配置

图片.png Redis7在这里发生了重大变化。原来只有一个appendonly.aof文件,现在具有了三类多个文件:

  • 基本文件:可以是RDF格式也可以是AOF格式。其存放的内容是由RDB转为AOF当时内存的快照数据。该文件可以有多个。
  • 增量文件:以操作日志形式记录转为AOF后的写入操作。该文件可以有多个。
  • 清单文件:用于维护AOF文件的创建顺序,保障激活时的应用顺序。该文件只有一个。

(3)混合式持久化开启

图片.png 对于基本文件可以是RDF格式也可以是AOF格式。通过aof-use-rdb-preamble属性可以选择。其默认值为yes,即默认AOF持久化的基本文件为rdb格式文件,也就是默认采用混合式持久化。

(4)AOF文件目录配置

图片.png 为了方便管理,可以专门为AOF持久化文件指定存放目录。目录名由appenddirname属性指定,存放在redis.conf配置文件的dir属性指定的目录,默认为Redis安装目录。

3.2AOF文件格式

AOF文件包含三类文件:基本文件、增量文件与清单文件。其中基本文件一般为rdb格式,在前面已经研究过了。下面就来看一下增量文件与清单文件的内容格式。

(1)Redis协议

增量文件扩展名为.aof,采用AOF格式。AOF格式其实就是Redis通讯协议格式,AOF持久化文件的本质就是基于Redis通讯协议的文本,将命令以纯文本的方式写入到文件中。

Redis协议规定,Redis文本是以行来划分,每行以\r\n 行结束。每一行都有一个消息头,以表示消息类型。消息头由六种不同的符号表示,其意义如下:

  • (+) 表示一个正确的状态信息
  • (-) 表示一个错误信息
  • (*) 表示消息体总共有多少行,不包括当前行
  • ($) 表示下一行消息数据的长度,不包括换行符长度\r\n
  • (空) 表示一个消息数据
  • (:) 表示返回一个数值

(2)查看AOF文件

打开appendonly.aof.1.incr.aof文件,可以看到如下格式内容。

图片.png

以上内容中框起来的是三条命令。一条数据库切换命令SELECT0,两条set命令。它们的意义如下

*2 -- 表示当前命令包含 2 个参数

$6 -- 表示第 1 个参数包含 6 个字符

SELECT -- 第 1 个参数

$1 -- 表示第 2 个参数包含 1 个字符

0 -- 第 2 个参数

*3 --表示当前命令包含 3 个参数

$3 -- 表示第 1 个参数包含 3 个字符

set -- 第 1 个参数

$3 -- 表示第 2 个参数包含 3 个字符

k11 -- 第 2 个参数

$3 -- 表示第 3 个参数包含 2 个字符

v11 -- 第 3 个参数

*3

(3)清单文件

打开清单文件 appendonly.aof.manifest,查看其内容如下:

图片.png

该文件首先会按照seq序号列举出所有基本文件,基本文件type类型为b,然后再按照seq序号再列举出所有增量文件,增量文件type类型为i。

对于Redis启动时的数据恢复,也会按照该文件由上到下依次加载它们中的数据。