redis持久化详解

RDB持久化

RDB持久化: 可以在执行的时间间隔内生成数据集的时间点快照(point-in-time snapshot),新快照会覆盖老快照。

优点

  1. 快速备份:RDB可以迅速为你创建一个数据的"快照",这是一个备份文件,方便你存储或者迁移数据。
  2. 启动快:当Redis重新启动时,RDB能帮助它更快速地加载数据,因为它直接读取一个完整的数据文件。
  3. 节省空间:与其他持久化方式相比,RDB的文件大小通常较小,因为它是经过压缩的。

缺点

  1. 可能丢数据:因为RDB只是不时地保存一次数据快照,如果在两次保存之间Redis出了问题,那中间的数据就可能会丢失。
  2. 有时会卡:在数据很多的情况下,创建 RDB 文件时可能会使服务器短暂地感觉有些卡顿。
  3. 卡顿的原因:尽管 Redis 使用写时复制(Copy-On-Write, COW)技术来减少内存的复制,fork( ) 在大数据集上的调用仍然可能相当耗时。这是因为操作系统需要为子进程准备一个与父进程相同的虚拟内存空间。在这个准备过程中,即使不立即复制物理内存,操作系统也需要复制和设置父进程的页表,这在数据集很大时会占用相当一部分时间。fork( ) 的执行时间与服务器上的数据量大小成正比。因此在数据集较大时,fork 可能会有比较久的延迟才能返回,所以才造成的卡顿。

RDB持久化工作原理

  1. 触发RDB生成:

触发 RDB 文件的生成有以下两种方式:

手动触发:通过执行 SAVE 或 BGSAVE 命令。

自动触发:基于 Redis 配置文件中的 save 指令设置的条件。(默认是通过 BGSAVE 命令来触发的)

  1. 创建子进程:

当执行 BGSAVE 命令时,Redis 主进程(父进程)会执行 fork 操作来创建一个子进程。这是一个昂贵的操作,尤其当数据集很大时。当 fork 操作执行后,子进程会获得父进程内存中的数据副本。但由于操作系统使用写时复制(Copy-On-Write, COW)技术,任何在父进程(Redis主进程)上发生的写操作不会影响子进程中的数据。这确保了子进程中的数据是隔离的,不受父进程中数据更改的影响。

  1. 子进程生成RDB文件:

子进程将开始遍历整个数据集,将所有的数据写入一个新的临时RDB文件。这是一个纯I/O操作,并且是线性的,所以非常快。子进程不需要处理任何客户端请求,只专注于写 RDB 文件,所以效率很高。

注意 :线性指的是数据在磁盘上是连续写入的。

  1. RDB文件替换:

一旦子进程完成了新的 RDB 文件的写入,它会替换掉旧的 RDB 文件,并发送一个信号通知父进程任务完成。然后子进程退出。

手动触发持久化

复制代码
# 前台进行持久化,会阻塞redis正常写入,直到持久化完成。
save

# 后台进行持久化,会开启子线程进行异步的持久化功能,不会阻塞redis正常写入。
bgsave

自动触发持久化

复制代码
# 900秒(15分钟)内有1个更改就会进行持久化。 
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /data/redis/data
# 如果后台保存数据出现错误,Redis 将停止所有写入操作。
stop-writes-on-bgsave-error  yes
# Redis在保存数据前先对其进行压缩,这样可以减少存储空间的使用。
rdbcompression  yes
# 在 RDB 文件末尾添加一个 CRC64 校验和,每次 Redis 保存或加载 RDB 文件时,它都会计算并检查这个校验和,确保数据的完整性。
rdbchecksum  yes

RDB 的载入与恢复

使用redis-cli shutdown 关闭redis, 在关闭之前会自动进行一次rdb持久化,并且开启之后会自动加载rdb文件恢复数据

AOF持久化

AOF持久化: 记录服务执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF文件中的命令全部以Redis协议的格式来保存,新命令会被追加到文件的末尾(append-only log file)。

优点

  1. 不轻易丢数据:AOF 记录了所有的写操作,所以即使服务器突然断电,数据丢失的机会也很小。
  2. 易于理解:AOF是一个文本文件,里面就是一系列的命令,你可以打开查看。
  3. 出问题也能救:如果 AOF 文件最后有点损坏,Redis 也能够修复它,避免大量数据丢失。

缺点

  1. 可能会慢一些:因为要不断写入操作,所以比 RDB 要慢一点。
  2. 文件可能很大:AOF 会记录所有操作,所以文件可能迅速增大,占用更多空间。
  3. 恢复时间长:如果需要从 AOF 文件中恢复数据,由于文件可能很大,所以这个过程可能会比较慢。

AOF 的工作原理

Redis 中的 AOF 持久化方式旨在持续地保存服务器上的所有修改操作。每当执行一个会改变数据的命令时,Redis 都会将该命令写入 AOF 文件中。这样,当 Redis 需要恢复数据时,只需执行 AOF 文件中的命令就可以恢复到原来的状态。

AOF 持久化的实现主要是以上三步:命令追加、文件写入、文件同步

  1. 命令追加: 将 redis 写操作命令追加到 aof_buf 缓冲区
  2. 文件写入: 周期性地将 aof_buf 缓冲区的命令写入 AOF 文件的内核缓冲区。
  3. 文件同步: 根据配置同步策略,将 AOF 文件缓冲区的内容同步到磁盘。

其中文件同步策略 redis 提供了三种,分别是以下三种:

  1. always:每次有命令写入时都立即同步。这提供了最高的数据安全性,但效率最低。
  2. everysec:每秒同步一次。这是一个权衡安全性和效率的策略。最多只丢失 1 秒 的数据
  3. no:让操作系统决定最佳的同步时间。这可能导致数据丢失,但提供了最高的效率。

AOF重写

AOF 重写,可以看作是对 AOF文件 进行的一次"精简"操作。它的目的是减少AOF文件的大小,并去除那些冗余的、不再必要的命令,使得该文件只包含恢复当前数据集所需的最小命令集。

为什么需要AOF重写?

节省磁盘空间:随着操作的积累,原始AOF文件可能会变得非常大。通过重写,我们可以减少文件的大小。

加速恢复速度:一个更小、更简洁的AOF文件意味着在Redis重启时,数据的恢复过程会更快。

AOF 重写的工作原理

AOF 重写主要有以下四步:

  1. redis 主进程 fork 子进程来进行 AOF 的重写,生成 AOF 文件。
  2. 在子进程进行 AOF 重写的同时,主进程继续处理客户端请求,并将新的写命令同时写入AOF 缓冲区和AOF 重写缓冲区,并按照appendfsync策略刷盘旧的AOF文件。
  3. 子进程完成重写完成后通知主进程,主进程将 AOF 重写缓冲区中的增量命令追加到新的 AOF 文件末尾(由主进程执行,而非直接写入新文件)。
  4. 使用新的 AOF 文件替换旧的 AOF 文件

子进程进行 AOF 重写,具体怎么重写,是根据现有的 AOF 文件进行重写还是其他方式?

子进程是通过读取 Redis 当前的内存数据来进行重写的。假如: redis 数据库存在列表键 List = [a,b,c,d,e,f,g,h] ,在旧的 AOF 文件中,可能有多个命令添加和删除这些元素。但在 AOF 重写时,子进程只需要看 List键 的当前状态,然后生成一个简短的命令,如 RPUSH List a b c d e f g h,直接设置正确的值,避免了任何冗余操作。

配置AOF持久化

复制代码
dir /data/redis/data
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite yes
aof-rewrite-incremental-fsync yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 1024mb
aof-load-truncated yes

AOF 文件的载入与恢复

使用redis-cli shutdown 关闭redis,在关闭之前会强制将AOF缓冲区全部写入磁盘,将所有未写入的内存数据追加到 AOF,当 Redis 服务器启动时,它会检查 AOF 文件的存在。如果找到 AOF 文件,Redis 会加载并执行其中的命令来恢复数据。

假如 Redis 的 RDB 和 AOF 持久化都启用,redis 在载入数据的时候,关机时会进行哪种备份?开机时是载入 AOF 文件?还是 RDB 文件?

关机时:RDB快照保存以及AOF追加都会进行。

开机时:Redis 会优先载入 AOF 文件来恢复数据,而不是 RDB 文件,虽然在正常关机时也会打一份rdb快照,但在意外宕机时只有AOF保证最近1秒内数据(取决于 appendfsync 配置),RDB 可能已经是很早以前的快照(比如几分钟前);

redis持久化详解

混合持久化

RDB 提供快速的数据恢复,但可能有数据丢失风险;AOF 保证了数据完整性,但文件可能过大,恢复速度较慢。那么,混合持久化是一种既快速又可靠的方法。

混合持久化是 Redis 4.0 新引入的持久化策略,结合了 RDB 的快速恢复和 AOF 的数据完整性的优点,它首先以 RDB 格式保存当前数据状态,然后继续以 AOF 格式记录新的写操作,确保数据完整性并优化恢复速度。

优点

  1. 更快的启动速度:混合持久化结合了RDB的速度优势,所以Redis可以更快地重新启动,不用等待很久。
  2. 数据安全:利用AOF的方式,即使服务器突然断电,也只会丢失极短的时间内的数据。
  3. 文件更小巧:因为混合持久化结合了 RDB 和 AOF 的优势,所以文件大小和冗余度都可以得到控制。
  4. 两全其美:简单说,它就是RDB和AOF的结合体,带来了两者的好处。

缺点

  1. 稍微复杂:因为它结合了两种技术,所以处理起来比单一的 RDB 或 AOF 要复杂一点。
  2. 可能占更多空间:在某些情况下,保存数据的文件可能会比只使用 RDB 或AOF 的文件要大一些。
  3. 写入速度:可能会稍慢一些,特别是当数据需要经常被保存到硬盘时(比如当 appendfsync 配置为"always"时)

混合持久化的工作原理

在 AOF 重写之前,RDB 和 AOF 都是按照它们各自的持久化策略工作的。当 AOF 重写被触发时,混合持久化才开始发挥作用:将当前的数据集会首先以RDB 格式写入新 AOF 文件的顶部,然后再追加新的命令到文件的末尾。

混合持久化的实现主要是靠主进程和子进程共同来完成的:

  1. 子进程进行 AOF 重写:
    • 首先创建临时新文件(非直接命名为 appendonly.rdb ,实际为带随机后缀的临时文件,最终原子替换时成为新 appendonly.aof )
    • 将 Redis 当前的数据生成 RDB 快照,以 RDB 二进制格式写入临时文件的开始部分(这部分作为混合 AOF 文件的RDB 前缀,用于快速恢复全量数据 )
    • 接着,子进程会把主进程 fork 时刻前,AOF 重写缓冲区中已积累的增量命令,以 AOF 文本命令格式续写至临时文件的后续位置(混合 AOF 的 AOF 后缀,用于补全精准增量 )
  2. 主进程进行追加:
    • 主进程在子进程重写期间,接收新写操作命令时,会同时写入两个缓冲区:
      • 原 AOF 缓冲区(aof_buf):按 appendfsync 策略刷盘至旧 AOF 文件,保证实时持久化不丢失
      • AOF 重写缓冲区(aof_rewrite_buf):专门记录 fork 后的新增命令,供子进程/主进程合并到新文件
    • 当子进程完成 RDB 前缀 + 初始 AOF 后缀 写入后,主进程会将 AOF 重写缓冲区中最新的增量命令,追加到临时文件的末尾(确保新文件包含 fork 后的所有操作,数据无遗漏 )
    • 子进程退出且主进程追加完成后,通过 rename 系统调用,将临时文件原子替换为新的 appendonly.aof 文件(原子操作保证替换过程不损坏文件,数据完整落地 )

混合持久化的配置

开启混合持久化:

复制代码
aof-use-rdb-preamble yes
# 并且要同时启用 RDB 和 AOF 两种持久化。

开启混合持久化后,Redis 不会单独生成 dump.rdb 文件,所有持久化数据(包括快照和增量命令)均写入 appendonly.aof 文件。

混合持久化的 AOF 重写与普通的 AOF 重写的区别

在不使用混合持久化的情况下,普通的 AOF 重写是通过读取当前的内存数据并记录达到这一状态所需的最少命令来减少 AOF 文件的大小的。而混合持久化在 AOF 重写时,会首先将当前数据集以 RDB 格式快照的形式写入新 AOF 文件的开始位置,然后再追加新的写命令到文件末尾。

混合持久化的载入与恢复

redis-cli shutdown关闭redis时,redis 会先生成当前内存数据的 RDB 快照,并将其写入 appendonly.aof文件的开头(作为前导),之后将AOF 缓冲区中未写入的写操作命令追加到 RDB 快照之后(确保关闭前的最后操作不丢失)。最后调用 fsync 确保文件完全落盘(受 appendfsync 配置影响,默认 everysec 可能延迟,但 shutdown 会强制同步)。

启动 Redis 时加载 RDB 前导,解析 RDB 部分,快速恢复内存数据(比逐条重放 AOF 命令更快)然后重放增量 AOF 命令,顺序执行 RDB 之后追加的 AOF 命令,将数据更新到最新状态。