Redis - 数据持久化

Redis持久化

Redis持久化的两种方式

Redis 支持两种主要的持久化存储方式,它们是:

  1. RDB(Redis DataBase)持久化

    • 在指定的时间间隔内生成 Redis 数据库的快照(snapshot)。
    • 快照是 Redis 数据在某个特定时间点上的副本,以二进制文件的形式存储在硬盘上。
    • RDB 持久化通过保存 Redis 在某个时间点上的数据快照来实现。
    • 这种方法对于备份 Redis 数据库以及在灾难恢复时非常有用,因为它提供了整个数据库的一致性快照。
    • RDB 持久化在配置文件中通过设置 save 指令来进行配置,你可以指定保存快照的条件和频率。
  2. AOF(Append Only File)持久化

    • AOF 持久化记录了对 Redis 服务器执行的所有写操作(append-only)。
    • Redis 以追加的方式将写命令追加到文件的末尾。
    • 通过重放 AOF 文件中的命令,Redis 可以重新构建整个数据集。
    • AOF 文件是一个简单的文本文件,可以通过检查其内容来了解 Redis 数据库的写操作历史。
    • AOF 持久化相比 RDB 持久化提供了更高的数据安全性,因为即使系统意外崩溃,也不会丢失太多数据。
    • 可以通过设置不同的同步选项来调整 AOF 持久化的性能和安全性,例如 alwayseverysecno

这两种持久化方式可以同时使用,也可以单独使用,具体取决于你对数据的要求和性能需求。

RDB

RDB持久化频次

在 Redis 6.2 之前和之后,对于 RDB(Redis DataBase)持久化的默认频率有所变化。

Redis 6.2 之前

默认情况下,Redis 采用的是基于时间的自动保存机制。在 redis.conf 配置文件中,通常会有以下配置:

1
2
3
save 900 1        # 在 900 秒(15 分钟)内,如果至少有 1 个 key 发生了变化,则触发保存操作
save 300 10       # 在 300 秒(5 分钟)内,如果至少有 10 个 key 发生了变化,则触发保存操作
save 60 10000     # 在 60 秒内,如果至少有 10000 个 key 发生了变化,则触发保存操作

Redis 6.2 及之后

1
save 3600 1 300 100 60 10000

save 3600 1: 表示在 3600 秒(1 小时)内,如果至少有 1 个 key 发生了变化,则触发保存操作。 save 300 100: 表示在 300 秒(5 分钟)内,如果至少有 100 个 key 发生了变化,则触发保存操作。 save 60 10000: 表示在 60 秒内,如果至少有 10000 个 key 发生了变化,则触发保存操作。

【注】自动触发 RDB 必须满足两个条件:一个是距离上次更新超过了 xxx 秒, 一个是在这段时间里达到了 xxx 次数, 满足这两个条件才会自动触发 save。

RDB自动触发和手动触发

RDB 持久化可以通过自动触发和手动触发两种方式来进行。

  1. 自动触发

    • 自动触发是指根据在 Redis 配置文件(通常是 redis.conf)中预先设置的条件,当满足这些条件时,Redis 会自动触发 RDB 持久化操作。
    • 在配置文件中,可以使用 save 指令来设置自动触发的条件。这个指令接受一系列的时间(单位为秒)和修改次数的对,表示在指定的时间内发生了指定数量的修改时,触发 RDB 持久化。
    • 例如,save 900 1 表示在 900 秒(15 分钟)内,如果至少有 1 个 key 发生了变化,则触发保存操作。
    • 在自动触发下,Redis 会根据配置的条件自动执行 RDB 持久化操作,无需手动干预。
  2. 手动触发

    • 手动触发是指通过发送命令给 Redis 服务器,显式地触发 RDB 持久化操作。

    • 可以使用 BGSAVE 命令手动触发 RDB 持久化。这个命令会在后台异步地生成 RDB 快照。

      BGSAVE 命令底层原理
       1. Fork子进程:
          - 当执行 `BGSAVE` 命令时,Redis 会创建一个子进程,该子进程将负责执行 RDB 快照的生成工作。
          - 在 Unix 系统中,Redis 使用了 `fork()` 系统调用来创建子进程,这样可以在不中断 Redis 服务的情况下执行 RDB 快照操作。
      
       2. Copy-on-write(写时复制)机制:
          - 在子进程创建后,Redis 通过 Copy-on-write 机制确保子进程与主进程共享内存。
          - Copy-on-write 机制意味着在子进程修改数据之前,它们会共享主进程的内存页。只有在需要修改数据时,才会复制内存页并进行修改,这样可以节省内存和时间。
      
       3. 遍历数据库:
          - 子进程会遍历 Redis 中的所有数据库,并将数据库中的键值对写入到临时文件中。
          - 在遍历过程中,Redis 使用了读取器来遍历数据结构,并通过持久化器将数据写入到临时文件中。
      
       4. 生成 RDB 文件:
          - 当遍历完成后,子进程会将临时文件保存为 RDB 文件,并覆盖现有的 RDB 文件(如果存在)。
          - 在保存完整个数据库状态后,子进程会向主进程发送信号,通知主进程 RDB 持久化操作已完成。
      
       5. 后台写入(Background Write):
          - 在上述过程中,子进程执行所有磁盘操作,而主进程继续处理客户端请求。
          - 这种方式称为后台写入,允许 Redis 在执行 RDB 持久化操作的同时继续处理客户端请求,避免了服务的停顿。
      
       通过以上步骤,Redis 在执行 `BGSAVE` 命令时会创建一个子进程,该子进程负责遍历数据库并生成 RDB 文件,而主进程则继续处理客户端请求,保证了服务的可用性和持久化的一致性。
      

    • 除了 BGSAVE,还可以使用 SAVE 命令来触发 RDB 持久化。不同的是,SAVE 命令会阻塞 Redis 服务器,直到 RDB 快照生成完毕才返回响应。

      生产上禁用SAVE 命令。

    • 手动触发适用于需要在特定时间点执行持久化操作,或者在特定场景下需要强制执行持久化操作的情况。

RDB优缺点

优点:

  • 快速恢复: RDB 备份生成的是 Redis 数据库的快照,因此在恢复时非常快速。只需将 RDB 文件加载到 Redis 中,就可以迅速恢复整个数据库状态。

    RDB 文件在内存中的加载速度要比 AOF 快很多,适合灾难恢复。

  • 节省空间: RDB 备份生成的是二进制文件,通常比 AOF 文件更加紧凑,占用的存储空间相对较小。

  • 按照业务定时备份: 可以根据业务需求定时执行 RDB 备份,以确保备份的及时性和有效性。

  • 最大限度地提高 Redis 性能: RDB 最大限度地提高了 Redis 的性能,因为 Redis 父进程为了持久化而需要做的唯一工作就是派生一个将完成所有其余工作的子进程。父进程永远不会执行磁盘 I/O 或类似操作。

缺点:

  • 数据丢失风险: RDB 备份是周期性的快照,因此在两次备份之间发生的数据变更会丢失。如果 Redis 服务器在备份之间发生故障,可能会丢失最近的数据更新。
  • 不适合实时应用: RDB 备份通常是异步执行的,因此不适合对数据要求实时性很高的应用场景。如果需要保证数据的实时性,可以选择使用 AOF 持久化。
  • 内存数据的全量同步: RDB 备份需要将内存中的数据全量同步到磁盘,如果数据量过大,可能会导致 IO 负载过重,影响服务器的性能。
  • fork 的性能影响: RDB 备份依赖于主进程的 fork 操作,对于较大的数据集来说,fork 操作可能会导致服务请求的瞬间延迟。在 fork 时,内存中的数据被克隆了一份,大致会导致两倍的内存膨胀,需要谨慎考虑和规划。

触发RDB快照

RDB 快照可以在以下情况下触发:

  1. 手动触发: 可以通过执行 SAVE 或者 BGSAVE 命令来手动触发 RDB 快照的生成。其中,SAVE 命令会阻塞 Redis 服务器的主线程,直到快照生成完成,而 BGSAVE 命令则会在后台异步执行生成快照。
  2. 自动触发: 在 Redis 配置文件中可以通过配置 save 指令来设置自动触发 RDB 快照的条件。当满足配置的条件时,Redis 将自动执行 RDB 快照的生成操作。例如,save 900 1 表示在 900 秒内,如果至少有 1 个 key 发生了变化,则触发保存操作。
  3. 执行 flushdb/flushall 命令: 执行 flushdb 或者 flushall 命令也会产生 dump.rdb 文件,但是这种方式会将命令记录到 dump.rdb 文件中,恢复后依旧是空,无意义。
  4. 关闭 Redis 服务器: 当关闭 Redis 服务器且没有设置开启 AOF 持久化时,会触发一次 RDB 快照的生成,用于保存当前数据库的状态。
  5. 主从复制: 在主从复制过程中,主节点可以通过发送 SYNC 命令通知从节点进行一次 RDB 快照的生成,用于初始化从节点的数据。

AOF

AOF持久化的工作流程

  1. Client 作为命令的来源,会有多个源头以及源源不断的请求命令。

  2. 这些命令到达 Redis Server 后,并不会直接写入 AOF 文件,而是先放入 AOF 缓存中进行保存。AOF 缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量或一定时间间隔后再一次性地写入磁盘,以避免频繁的磁盘 IO 操作。

  3. AOF 缓冲区会根据 AOF 缓冲区同步文件的 三种写回策略,将命令写入磁盘上的 AOF 文件。

  4. 随着写入 AOF 内容的增加,为避免 AOF 文件膨胀,Redis 会根据配置的规则进行 AOF 重写(AOF Rewrite),即对 AOF 文件进行重写并压缩,将历史命令进行合并,生成一个新的 AOF 文件。

  5. 当 Redis Server 服务器重启时,会从 AOF 文件中载入数据,根据 AOF 文件中记录的命令操作来恢复数据库的状态。

AOF持久化工作流程

AOF缓冲区三种写回策略

Always:同步写回,每个写命令执行完立刻同步地将日志写会磁盘;

Everysec:每秒写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔1秒把缓冲区中的内容写入到磁盘;

No:操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

AOF三种写回策略

AOF文件的相关配置

开启aof

1
appendonly yes

使用默认写回策略

1
2
3
# appendfsync always
appendfsync everysec
# appendfsync no

aof 文件 - 保存路径

  • redis6 及以前

    AOF 保存文件的位置和 RDB 保存文件的位置一样,都是通过 redis.conf 配置文件的 dir 配置。

  • redis7 最新

    通过 appenddirname 参数,配置 AOF 文件的路径,会在 dir 配置的路径下,单独新建一个文件夹(appenddirname 参数中设置的名称),AOF 文件的路径为:dir + appenddirname。

aof 文件 - 保存名称

  • redis6 及以前,有且仅有一个,即:

    1
    2
    
    # redis6 及以前,aof 文件的默认名称
    appendfilename "appendonly.aof"
  • redis7:Multi Part AOF 的设计,从 1 个文件到 3 个文件。

    MP-AOF 就是将原来的单个 AOF 文件拆分成多个 AOF 文件。在 MP-AOF 中,我们将 AOF 分为三种类型,分别为:

    • BASE: 表示基础 AOF,它一般由子进程通过重写产生,该文件最多只有一个。

    • INCR: 表示增量 AOF,它一般会在 AOFRW 开始执行时被创建,该文件可能存在多个。

    • HISTORY: 表示历史 AOF,它由 BASE 和 INCR AOF 变化而来,每次 AOFRW 成功完成时,本次 AOFRW 之前对应的 BASE 和 INCR AOF 都将变为 HISTORY,HISTORY 类型的 AOF 会被 Redis 自动删除。

为了管理这些 AOF 文件,我们引入了一个 manifest (清单) 文件来跟踪、管理这些 AOF。同时,为了便于 AOF 备份和拷贝,我们将所有的 AOF 文件和 manifest 文件放入一个单独的文件目录中,目录名由 appenddirname 配置 (Redis 7.0 新增配置项) 决定。

Redis7.0config 中对应的配置项

redis7AOF配置项

AOF的优缺点

优点:

  1. 更可靠的持久性:使用 AOF 持久化可以通过不同的 fsync 策略来控制数据持久性。通过选择每秒 fsync 的默认策略,您可以保证写入性能仍然很高,同时最多只会丢失一秒钟的写入数据。fsync 是在后台线程执行的,这意味着即使在进行 fsync 时,主线程仍然可以继续努力执行写入操作,从而最大限度地减少了对性能的影响。

  2. 更好的容错性:AOF 日志是一个仅追加的日志,因此不会出现寻道问题,也不会在断电时出现损坏问题。即使由于某种原因(比如磁盘已满或其他原因)导致日志以写一半的命令结尾,Redis 的工具 redis-check-aof 可以轻松修复它,确保数据的完整性和一致性。

  3. 自动重写机制:当 AOF 文件变得太大时,Redis 能够在后台自动对 AOF 文件进行重写。重写操作是完全安全的,因为在继续追加到旧文件时,Redis 会使用最小的操作集来生成一个全新的文件,一旦第二个文件准备就绪,Redis 就会切换到新文件并开始追加操作。这有助于减小 AOF 文件的大小,并确保 Redis 在长期运行时仍然能够高效地处理写入操作。

  4. 易于理解和导出的格式:AOF 以易于理解和解析的格式依次包含所有操作的日志。这意味着您可以轻松地导出 AOF 文件,并在需要时进行检查和分析。例如,即使您不小心使用了 FLUSHALL 命令刷新了所有内容,只要在此期间没有执行日志重写,您仍然可以通过停止服务器、删除最新命令并重新启动 Redis 来恢复数据集,从而避免了数据丢失的风险。

缺点:

  1. 文件大小和磁盘空间占用: 相同数据集的情况下,AOF 文件通常要远大于 RDB 文件,因为 AOF 记录了每个写操作的详细信息。这可能导致 AOF 文件占用更多的磁盘空间,尤其是在高写入负载下,AOF 文件的增长速度会更快,可能会导致磁盘空间不足的问题。
  2. 恢复速度较慢: 相比于 RDB 持久化,AOF 持久化的恢复速度通常较慢。当 AOF 文件非常大时,Redis 在重启时需要重新执行整个 AOF 文件以恢复数据,这可能会导致较长的恢复时间,尤其是在 AOF 文件非常庞大时。

AOF的重写机制

AOF 文件的重写机制是 Redis 用于优化 AOF 持久化性能和减小 AOF 文件大小的一项重要功能。当 AOF 文件变得过大时,重写机制可以帮助 Redis 在后台自动重新生成一个新的 AOF 文件,从而减小文件大小并提高性能。

一句话:启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。

以下是 AOF 文件的重写机制的工作原理:

  1. 触发条件: Redis 会监测 AOF 文件的大小,并在达到预设阈值时触发 AOF 重写操作。这个阈值可以通过配置选项进行设置,通常是通过设定 AOF 文件大小与上次重写后数据变动的比例,或者直接指定 AOF 文件的最大大小。

  2. 重写过程: 当触发条件满足时,Redis 将在后台启动 AOF 文件的重写过程(“重写子进程”)。这个过程不会阻塞 Redis 的正常操作,因此不会对客户端的请求产生影响。

    主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的 AOF 文件中,这样做是保证原有的 AOF 文件的可用性,避免在重写过程中出现意外。

    当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。

  3. 重写算法: AOF 重写的算法是基于 Redis 当前的数据集状态生成新的 AOF 文件。它会分析当前数据集的状态,并使用生成一个包含最小操作集的新的 AOF 文件,该操作集可以重建出完整的数据集。

  4. 原子性操作: 在 AOF 重写过程中,Redis 会确保生成的新 AOF 文件是原子性的。这意味着在 AOF 文件切换之前,Redis 会先将新文件创建完整,然后一次性切换到新文件上进行写入操作。这样可以确保数据的一致性和完整性。

  5. 文件切换: 一旦新的 AOF 文件生成完成,Redis 将会切换到新文件上进行写入操作。这样新的写入操作将不再追加到旧的 AOF 文件上,而是直接写入到新的 AOF 文件上。

  6. 删除旧文件: 在切换完成后,Redis 可以选择删除旧的 AOF 文件,释放磁盘空间。但是为了保险起见,通常会等待一段时间,确保新的 AOF 文件已经被持久化到磁盘上,然后再进行删除操作。

触发AOF的重写机制

  1. 手动触发:
  • 管理员可以手动触发 AOF 的重写操作,以便在需要的时候进行文件大小的优化和性能的提升。这通常通过发送 BGREWRITEAOF 命令来实现。执行该命令后,Redis 将在后台启动 AOF 重写过程。
  1. 自动触发:
  • 自动触发是基于配置的阈值来触发 AOF 重写操作的。当 AOF 文件大小达到一定的阈值时,Redis 会自动启动 AOF 重写过程。

  • 这个阈值可以通过配置选项来设置,通常是根据 AOF 文件的大小与上次重写后数据变动的比例,或者直接指定 AOF 文件的最大大小。

    redis.conf 配置文件默认配置:

    auto-aof-rewrite-percentage:默认值为100;

    auto-aof-rewrite-min-size:64mb配置。

    也就是说默认 Redis 会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于64M时触发。

  • 一旦达到了触发条件,Redis 将在后台自动启动 AOF 重写过程,以优化 AOF 文件的大小和性能。

RDB和AOF的优先级

当 Redis 同时启用了 RDB 和 AOF 持久化时,通常会按照以下顺序进行加载:

  1. AOF 文件的加载优先级较高:

    • 如果 Redis 在启动时检测到存在 AOF 文件(即启用了 AOF 持久化),它会优先加载 AOF 文件来恢复数据。这是因为 AOF 文件记录了 Redis 自上次启动或者上次 AOF 文件重写以来的所有写操作,因此可以确保恢复到最新的数据状态。
  2. 如果没有 AOF 文件,才会考虑加载 RDB 文件:

    • 如果 Redis 启动时没有检测到 AOF 文件,它会尝试加载 RDB 文件来恢复数据。RDB 文件是一个快照文件,记录了 Redis 在某个时间点的完整数据状态。尽管 RDB 文件提供了一种快速恢复数据的方式,但它可能会使您丢失最后一次 AOF 文件中记录的一些写操作。
  3. 如果既没有 AOF 文件也没有 RDB 文件:

    • 如果 Redis 启动时既没有检测到 AOF 文件也没有 RDB 文件,它将启动一个空的数据库。

同时使用两者时服务器重启也只会找 AOF 文件。但是作者也不建议只使用 AOF 方式备份,因为 RDB 更适合用于备份数据库(AOF 在不断的变化不好备份),留着 RDB 作为一个万一的手段。

RDB-AOF混合持久化

开启,在 redis.conf 文件中,将aof-use-rdb-preamble参数设置为yes

1
aof-use-rdb-preamble yes

先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。

简单来说:混合持久化方式产生的文件一部分是 RDB 格式,一部分是 AOF 格式。AOF 包括了 RDB 头部 + AOF 混写。

纯缓存模式

同时关闭RDB+AOF,专心做缓存

  1. save "" – 禁用RDB

    禁用RDB持久化模式下,我们仍然可以使用命令save、bgsave生成RDB文件。

  2. appendonly no – 禁用AOF

    禁用AOF持久化模式下,我们仍然可以使用命令bgrewriteaof生成AOF文件。

0%