Skip to content

Redis的持久化(persistence)

Redis支持将内存中数据写入硬盘存储,防止数据丢失,持久化办法有三种,分别是RDB(Redis Database)、AOF(Append Only File)和RDB+AOF。 Alt text

1. RDB方式

在指定的时间间隔,执行数据集的时间点全量快照📷,写入到磁盘中,其中快照文件就称为RDB文件(dump.rdb)

1.1 RDB配置参数说明

  1. save <seconds> <changes> [<seconds <changes>...]: 表示连续设置一个或多个m秒内数据集存在n次修改时,自动触发持久化。
  2. dbfilename: RDB快照文件的文件名。
  3. dir: RDB快照文件保存的文件夹。
  4. stop-writes-on-bgsave-error: 默认yes, 如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制这种不一致,那么在快照写入失败时,也能确保redis继续接受新的写请求。
  5. rdbcompression: 默认yes, 对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能。
  6. rdbchecksum: 默认yes, 在存储快照后,还可以让Redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
  7. rdb-del-sync-files: 在没有持久性的情况下删除复制中使用的RDB文件启用。默认情况下no,此选项是禁用的。

1.2 自动RDB配置

  1. 配置redis.conf文件
    • Redis6.0.16之前版本
      修改SNAPSHOTTING节点save参数,来触发Redis自动持久化。
      其中save的格式:save m n 表示m秒内数据集存在n次修改时,自动触发持久化,默认策略是: Redis6.0.16之前版本默认策略RDB图
    • Redis6.0.16之后版本
      修改SNAPSHOTTING节点save参数,来触发Redis自动持久化。
      默认策略是: save 3600 1 300 100 60 10000
      每隔1小时,如果有超过1个key发生改变,就写一次新的RDB文件。
      每隔5分钟,如果有超过100个key发生改变,就写一次新的RDB文件。
      每隔1分钟,如果有超过10000个key发生改变,就写一次新的RDB文件。

1.3 手动设置RDB

Redis提供了两个命令来生成RDB文件,分别是savebgsave

  1. save命令
    语法:SAVE
    在主程序中执行会阻塞当前redis服务器,直到持久化工作完成执行save命令期间,Redis不能处理其他命令,线上禁止使用
  2. bgsave命令
    语法:BGSAVE [SCHEDULE]
    Redis会在后台异步进行快照操作,不阻塞快照同时还可以响应客户端请求,该触发方式会fork一个子进程由子进程复制持久化过程。
    当Redis正在执行BGSAVEAOF rewrite操作时,此时再执行bgsave就会报错,如果使用BGSAVE SCHEDULE,Redis执行该命令将立即返回OK,并将请求记录后台保存,安排空闲时运行bgsave操作。
sh
192.168.101.105:6379> BGSAVE
Background saving started
  1. lastsave命令
    语法:LASTSAVE
    返回最后一次保存RDB文件的UNIX时间戳, 可以用来监控查询BGSAVE异步保存RDB文件是否完成。
sh
192.168.101.105:6379> LASTSAVE
(integer) 1710049761
192.168.101.105:6379> bgsave
Background saving started
192.168.101.105:6379> lastsave
(integer) 1710057622

可以发现两次lastsave命令返回时间戳不同,即可认为bgsave已经执行完成。如需转换时间戳可以使用linux的data命令,比如:

sh
## 得到具体日期
[root@hadoop105 redis-7.2.4]# date -d @1710057622
2024年 03月 10日 星期日 16:00:22 CST

1.4 配置RDB文件位置

  1. 获取当前RDB文件位置
sh
192.168.101.105:6379> config get dir
1) "dir"
2) "/opt/module/redis-7.2.4/bin"
  1. 修改RDB文件位置和文件名
sh
[jack@hadoop105 redis-7.2.4]$ vi conf/redis.conf
# dir ./      改为    dir /opt/module/redis-7.2.4/data/
# dbfilename dump.rdb    改为     dbfilename   master6379.rdb

## 修改配置后重启redis
[root@hadoop105 redis-7.2.4]# ./bin/redis-server ./conf/redis.conf
## 远程连接redis查看配置
192.168.101.105:6379> config get dir
1) "dir"
2) "/opt/module/redis-7.2.4/data"

警告

  1. flushdb清空Redis,是不能恢复数据的,原因在于执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的, 已经失去备份恢复意义。
  2. 不可以在生产上把备份文件dump.rdb和redis服务器放在同一台机器,必须分开各自存储,以防生产机物理损坏后备份文件也挂了。
  3. rdb文件在redis数据库中只有一个,如果想要备份RDB文件,可以执行bgsave命令生成的RDB文件重命名为带有时间戳的文件名,以此保留多个历史快照。

1.5 RDB优缺点

  1. RDB优点
    • RDB是Redis数据的一个非常紧凑的单文件快照。RDB文件非常适合备份。提供很自由的保存RDB快照的规则,这使您可以在发生灾难时轻松恢复不同版本的数据集。
    • RDB非常适合灾难恢复,它是一个可以传输到远程数据中心或Amazon S3(可能已加密)的压缩文件。
    • RDB最大限度地提高了Redis的性能,因为Redis父进程为了持久化而派生一个子进程。父进程永远不会执行磁盘I0或类似操作。与AOF相比,RDB允许使用大数据集更快地重启。
    • 在副本上,RDB支持重启和故障转移后的部分重新同步
  2. RDB缺点
    • 如果您需要在Redis停止工作时(例如断电后)将数据丢失的可能性降到最低,那么RDB并不好。配置生成RDB的不同保存时间点,而在这期间都可能Redis不正确的关闭而丢失最新的数据。
    • RDB需要经常fork()以便使用子进程在磁盘上持久化。如果数据集很大,fork()也可能会很耗时,并且如果数据集很大并且CPU性能不是很好,可能会影响Redis为客户端服务几秒甚至一秒钟。

1.6 修复RDB文件

使用RDB文件检查工具redis-check-rdb可以处理常见的rdb问题。

sh
[root@hadoop105 bin]# ./redis-check-rdb ../data/master6379.rdb
[offset 0] Checking RDB file ../data/master6379.rdb
[offset 26] AUX FIELD redis-ver = '7.2.4'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1710057621'
[offset 67] AUX FIELD used-mem = '1283176'
[offset 79] AUX FIELD aof-base = '0'
[offset 81] Selecting DB ID 0
[offset 187] Checksum OK
[offset 187] \o/ RDB looks OK! \o/
[info] 4 keys read
[info] 0 expires
[info] 0 already expired

1.7 触发写入RDB文件条件

  • 配置文件中默认的快照配置
  • 手动save/bgsave命令
  • 执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的,无意义
  • 执行shutdown且没有设置开启AOF持久化
  • 主从复制时,主节点自动触发

1.8 禁用RDB快照

  1. 动态修改停止RDB保存快照
    使用config set save命令, 将保存快照规则重置为空字符串即可,缺点是重启Redis后配置信息丢失。
sh
192.168.101.105:6379> config set save ""
OK
  1. 修改redis.conf文件
ini
## 新增一行
save ""

重启Redis服务器即可生效。

2. AOF方式

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,Redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

2.1 AOF工作流程

AOF工作流程图

步骤详情
1Client作为命令的来源,
会有多个源头以及源源不断的请求命令。
2在这些命令到达Redis Server以后并不是直接写入AOF文件,
会将其这些命令先放入AOF缓存中进行保存。
这里的AOF缓冲区实际上是内存中的一片区域,
存在的目的是当这些命令达到一定量以后再写入磁盘,
避免频繁的磁盘IO操作。
3AOF缓冲会根据AOF缓冲区同步文件的三种写回(fsync)策略
将命令写入磁盘上的AOF文件。
4随着写入AOF内容的增加为避免文件膨胀,
会根据规则进行命令的合并(又称AOF重写)
从而起到AOF文件压缩的目的。
5当Redis Server服务器重启的时候会从AOF文件载入数据。

2.2 AOF配置参数

  1. appendonly: 是否开启AOF
  2. appendfsync: 指定写回策略,总共三种:alwayseverysecno,默认为everysec
    • always: 同步写回,每个写命令执行完立刻同步地将日志写回磁盘。
    • everysec: 每秒写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔1秒把缓冲区中的内容写入磁盘。
    • no: 操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
  3. appenddirname: AOF文件的保存路径, 不同版本的配置不同:
    • Redis6以及之前版本: AOF保存文件的位置和RDB保存文件的位置一样,都是读取dir配置
    • Redis7版本: AOF保存文件的文件夹位置=dir+appenddirname
  4. appendfilename: AOF文件名称,在Redis7中,基于新的Multi Part AOF的设计,aof文件不再是Redis7之前的单文件,有三个文件组成:base基本文件,incr增量文件,manifest清单文件。
  5. auto-aof-rewrite-percentage: 相比上次重写文件增长占比
  6. auto-aof-rewrite-min-size: 重写需要最小文件大小
  7. no-appendfsync-on-rewrite: aof重写期间是否同步

2.3 开启AOF

  1. 修改redis.conf配置
sh
[root@hadoop105 bin]# vi ../conf/redis.conf 
 appendonly no改为  appendonly yes 
appendfsync默认配置不动
appenddirname "data"
appendfilename配置不动
  1. 重启Redis服务器
sh
[root@hadoop105 bin]# ./redis-cli -a jack shutdown
[root@hadoop105 bin]# ./redis-server ../conf/redis.conf
[root@hadoop105 bin]# cd ../data
[root@hadoop105 data]# ll
总用量 8
-rw-r--r--. 1 root root 88 3月  10 20:22 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root  0 3月  10 20:22 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 3月  10 20:22 appendonly.aof.manifest

2.4 AOF优缺点

  1. AOF优点
    • 使用AOF的Redis持久化程度高: 支持不同的写回策略,写回是使用后台线程执行的,基本不丢失写入日志。
    • AOF日志是一个追加日志,不会出现寻道问题,也不会在断电时出现损坏问题。即使由于某种原因(磁盘已满或其他原因)日志以写一半的命令结尾,使用redis-check-aof工具也能够轻松修复它。
    • 当AOF变得太大时,Redis能够在后台自动重写AOF。重写是完全安全的,因为当Redis继续附加到旧文件时,会使用创建当前数据集所需的最少操作集生成一个全新的文件,一旦第二个文件准备就绪,Redis就会切换两者并开始附加到新的那一个。
    • AOF以易于理解和解析的格式依次包含所有操作的日志。您甚至可以轻松导出AOF文件。例如,即使您不小心使用FLUSHALL命令刷新了所有内容,只要在此期间没有执行日志重写,您仍然可以通过停止服务器、删除最新命令(就是FLUSHALL)并重新启动Redis来保存您的数据集。
  2. AOF缺点
    • AOF文件通常比相同数据集的RDB文件大。
    • 有些写回策略下AOF可能比RDB慢。

2.5 AOF重写机制

随着Redis持久化的不断进行,AOF的文件会越来越大,文件越大占用服务器内存越大以及AOF恢复要求时间越长。
为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的峰值时,Redis就会自动或者手动使用bgrewriteaof命令启动AOF文件的内容压缩,AOF文件只保留可以恢复数据的最小指令集。

  1. 自动触发
sh
## 在redis.conf默认触发条件:
## AOF文件大小是上次rewrite后大小的一倍并且文件大于64M时进行重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
  1. 手动触发 客户端向服务器发送bgrewriteaof命令。
sh
192.168.101.105:6379> bgrewriteaof
Background append only file rewriting started
## 查看aof文件
[root@hadoop105 data]# ll
总用量 8
-rw-r--r--. 1 root root 88 3月  10 21:39 appendonly.aof.2.base.rdb
-rw-r--r--. 1 root root  0 3月  10 21:39 appendonly.aof.2.incr.aof
-rw-r--r--. 1 root root 88 3月  10 21:39 appendonly.aof.manifest
  1. 重写流程
    a. Redis的父进程进行forks一个子进程,这个子进程会子进程会遍历Redis服务器的内存数据,针对每个键依据其当前状态生成对应的写命令,并将这些命令写入临时AOF文件。
    b. 与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
    c. 当重写子进程完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。
    d. 当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中。
    e. Redis将使用base临时aof文件生成新的base文件和删除旧的增量文件。

3. RDB+AOF混合持久化

Redis支持RDB和AOF同时开启,RDB和AOF共存时,Redis重启运行加载AOF的优先级更高, Redis重启加载优先级

3.1 开启混合方式

更改redis.conf文件配置

sh
[root@hadoop105 appendonlydir]# vi ../conf/redis.conf
## 启用 RDB + AOF 混合持久化
aof-use-rdb-preamble yes

RDB+AOF混合持久化是Redis4.0引入的功能。它在AOF重写时,将重写时刻的内存数据以RDB格式写入AOF文件头部,后续新的写操作仍以AOF格式追加到文件末尾。这样生成的AOF文件前半部分是RDB格式的快照,后半部分是AOF格式的命令日志。

3.2 工作流程

  1. 正常运行阶段
    Redis服务器正常运行时,若开启了AOF持久化,所有写命令会被追加到AOF文件末尾。
  2. AOF重写触发
    当满足AOF重写的条件(如手动执行BGREWRITEAOF命令或达到自动重写阈值)时,开始AOF重写流程:
    • 创建子进程:Redis主进程通过fork()系统调用创建子进程。子进程复制主进程的内存空间,和主进程共享相同的数据。
    • 生成RDB快照:子进程将当前内存中的数据以RDB格式写入到临时AOF文件的头部。
    • 记录新命令:在子进程生成RDB快照期间,主进程继续处理客户端的写命令,将这些命令同时记录到现有的AOF文件和AOF重写缓冲区中。
    • 追加AOF命令:子进程完成RDB快照写入后,主进程将AOF重写缓冲区中的命令以AOF格式追加到临时AOF文件的末尾。
    • 替换旧文件:主进程用临时AOF文件替换旧的AOF文件。
  3. 数据恢复阶段
    当Redis重启时,会加载AOF文件进行数据恢复, 包括下面两大部分:
    • 加载RDB部分:Redis先解析AOF文件的RDB部分,快速将内存数据恢复到AOF重写时的状态。
    • 执行AOF命令:接着按顺序执行AOF文件后半部分的写命令,恢复重写之后的增量数据。