Redis持久化之RDB(七)

1. 总体介绍

Redis是一个基于内存的数据库,它的数据时存放在内存中,内存有个问题就是关闭服务或者断电会丢失。

Redis的数据也支持写到硬盘中,这个过程就要持久化。Redis提供了4种不同的持久化方式:

  • RDB(Redis Database)

  • AOF(Append Of File)

  • 虚拟内存(VM) –reids2.4已经弃用

  • DISKSTORE

2. RDB(Redis Database)

2.1. RDB介绍

在指定的时间间隔内将内存中的数据集快照(snapshot)写入磁盘,它恢复时是将快照文件直接读到内存里

2.2. 备份是如何执行的

Redis会单独创建(fork)一个子进程进行持久化,会将数据写入到一个临时文件中,待持久化过程都结束后,
再用这个临时文件替换上次持久化好的文件中,整个过程中主进程不进行任何IO操作,这就是确保了极高的性能。如果需要进行大规模的恢复,且对数据恢复的完整性不是非常敏感,那RDB方式要比AOF更加高效,

RDB的缺点是最后一次持久化后的数据可能丢失。

2.3. Fork

  • Fork的作用是复制一个与当前进程一样的进程,新进程的所有数据(变量、环境变量、程序计数器等)数值和原进程一致,它是一个全新的进程,并作为原进程的子进程

  • 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后会多次exec系统调用,出于效率考虑,Linux中引入了”写时复制技术””

  • 一般情况弗进程和子进程会共用一段物理内存,只有进程空间的各段的内容要发生变化是,才会将父进程的内容复制一份给子进程。

2.4. RDB持久化流程

2.5. 指定备份文件的名称

在redis.conf中,可以修改rdb备份文件的名称(dbfilename)以及保存路径(dir),默认为dump.rdb,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# sanitize-dump-payload no

# The filename where to dump the DB
dbfilename dump.rdb


# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
# ./表示执行redis-server命令启动redis时所在的目录
dir ./

2.6. 触发RDB备份

  1. 方式1:自动备份

    以下4中情况会自动触发:

    • redis.conf中配置save m n,即在m秒内有n次修改时,自动触发bgsave生成rdb文件;

      save用来配置备份规则, 格式为:save 秒 写操作次数默认是1分钟内修改了1万次,或5分钟内需修改了10次,或30分钟内修改了1次。

      示例:设置20秒内有最少3次key发生备份,则进行备份

      1
      save 20 3
    • 主从复制时,从节点要从主节点进行全量复制时也会触发bgsave操作,生成当时的快照发送到从节点;

    • 执行debug reload命令重新加载redis时也会触发bgsave操作;

    • 默认情况下执行shutdown命令时,如果没有开启aof持久化,那么也会触发bgsave操作;

  2. 方式2:手动执行命令备份(save | bgsave)

    触发备份有两个命令:

    • save:阻塞当前Redis服务器,直到RDB过程完成为止,手动保存,不建议使用

    • bgsave:redis会在后台一步进行快照操作,快照同时还可以响应客户端情况,可以通过lastsave命令获取最后一次生成快照的时间

      具体流程如下:

      • redis客户端执行bgsave命令或者自动触发bgsave命令;
      • 主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回;
      • 如果不存在正在执行的子进程,那么就fork一个新的子进程进行持久化数据,fork过程是阻塞的,fork操作完成后主进程即可执行其他操作;
      • 子进程先将数据写入到临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件;
      • 同时发送信号给主进程,通知主进程rdb持久化完成,主进程更新相关的统计信息(info Persitence下的rdb_*相关选项)。#
  1. 方式3: flushall命令

    执行flushall命令,也会产生dump.rdb文件,但是里面是空的,无意义。

redis.conf其他的一些配置

  1. stop-writes-on-bgsave-error:当磁盘满时,是否关闭redis的写操作,默认yes

  2. rdbcompression:rdb备份是否开启压缩

    对于存储到磁盘中的rdb快照文件,可以设置是否进行压缩,如果是的话,redis采用LZF算法进行压缩,默认yes

  3. rdbchecksum:是否检查rdb备份文件的完整性

    存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样会加大性能消耗,如果希望获取最大的性能,可以关闭,默认 yes

2.7. rdb的备份和恢复

  1. 获取rdb文件的目录

    1
    2
    3
    127.0.0.1:6379> config get dir
    1) "dir"
    2) "/usr/local/redis/src"
  2. 将rdb的备份文件*.rdb文件拷贝到其他地方

    1
    2
    cd /usr/local/redis/src
    cp dump.rdb dump2.rdb
  3. rdb恢复

    • 关闭redis
    • 把备份的文件拷贝到工作目录/usr/local/redis/src,比如cp dump2.rdb dump.rdb
    • 启动redis,备份数据直接加载,数据恢复

2.8. 优缺点

优势:

  • 适合大规模数据恢复

  • 对数据完整性和一致性要求不高更适合使用

  • 节省磁盘空间

  • 恢复速度块

劣势:

  • Fork的时候,内存中的数据会被克隆一份,大致2倍的膨胀,需要考虑

  • 虽然Redis在fork的时候使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能

  • 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down的话,就会丢失最后一次快照后所有修改

2.9. 停止RDB

动态停止RDB:redis-cli config set save "" #save后给空值,表示禁用保存策略。

3. RDB深入理解

RDB中的核心思路是Copy-on-Write,来保证快照操作的时间,需要压缩写入磁盘上的数据在内存中不会发生便哈,在正常的快照操作中,一方面Redis主进程会fork一个新的快照进程专门处理这个事情,这样保证了Redis服务不会停止对
客户端包括写请求在哪的任何响应。另一方面这段时间发生的数据变化会以副本的方式存放在另一个新的内存区域,等到快照操作结束后才会同步到原来的内存区域。

举个例子:如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。

3.1. 快照间隔时间

对于快照来说,所谓“连拍”就是指连续地做快照。这样一来,快照的间隔时间变得很短,即使某一时刻发生宕机了,因为上一时刻快照刚执行,丢失的数据也不会太多。但是,这其中的快照间隔时间就很关键了

如果频繁地执行全量快照,也会带来两方面的开销

  • 一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
  • 另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了。

4. RDB优缺点

优点:

  • RDB文件是某个时间节点的快照,默认使用LZF算法进行压缩,压缩后的文件体积远远小于内存大小,适用于备份、全量复制等场景;
  • Redis加载RDB文件恢复数据要远远快于AOF方式;

缺点:

  • RDB方式实时性不够,无法做到秒级的持久化;
  • 每次调用bgsave都需要fork子进程,fork子进程属于重量级操作,频繁执行成本较高;
  • RDB文件是二进制的,没有可读性,AOF文件在了解其结构的情况下可以手动修改或者补全;
  • 版本兼容RDB文件问题;针对RDB不适合实时持久化的问题,Redis提供了AOF持久化方式来解决#