Redis 学习 - 04 持久化

介绍Redis的两种持久化方式:RDB和AOF。RDB通过快照保存数据集,适合备份和灾难恢复;AOF记录所有写操作命令,更加持久可靠。

参考

Redis 持久化(Persistence)

Redis 的强劲性能很大程度上是由于其将所有数据都存储在内存中,然而当 Redis 重启或宕机后,所有存储在内存中的数据就会丢失。在一些情况下,我们会希望 Redis 在重启后能够保证数据不丢失。

这时我们希望 Redis 能将数据从内存中以某种形式同步到硬盘中,使得重启后可以根据硬盘中的记录恢复数据。这一过程就是持久化。

Redis 提供了两种持久化方案:

  • RDB(Redis Database):根据指定的规则“定时”将内存中的数据快照存储在硬盘上,在重启之后读取硬盘上的 .rdb 快照文件将数据恢复到内存中。
  • AOF(Append Only File):记录服务器执行的所有写操作命令,形成 .aof 日志文件保存到硬盘中,并在服务器启动时,通过重新执行这些命令来还原数据集(重建当前状态)。

以及另外两个持久化选择:

  • No persistence:无持久化,完全禁用持久化,让数据只在服务器运行时存在。
  • RDB + AOF:可以在同一实例中组合 RDB 和 AOF。注意,在这种情况下,当 Redis 重新启动时,将优先使用 AOF 文件还原数据集,因为它存的数据通常比 RDB 更完整。

要理解的最重要的事情是 RDB 和 AOF 之间的不同权衡。

RDB 持久化(Snapshotting)

RDB 方式的持久化是通过快照完成的,当符合一定条件时 Redis 会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程即为**“快照”**。

默认情况下,Redis 将快照保存在名为 dump.rdb 的二进制文件中。

RDB 触发机制

RDB 触发机制分为:

  • 手动触发:手动调用 SAVEBGSAVE 命令
    • SAVE:同步执行,会阻塞当前 Redis 服务器,执行期间,Redis 不能处理其它命令,直到 RDB 完成
    • BGSAVE:异步执行,Redis 进程执行 fork(派生)操作创建子进程,RDB 持久化过程由子进程负责,子进程将数据集写入到临时 RDB 文件,完成后替换旧的 RDB 文件,子进程自动结束。持久化期间仍然可以处理其它命令。
      • Redis 只会在 fork 期间发生阻塞,但一般时间很短,但如果 Redis 数据量特别大, fork 时间就会边长,且占用内存会加倍。
  • 自动触发:通过在配置文件 redis.conf 中配置快照条件,当满足条件时,Redis 自动执行快照操作(执行 BGSAVE 指令触发的函数)。

RDB 自动触发条件配置

自动触发快照的条件有两个:

  • seconds:表示当前距离上一次持久化的时间
  • changes:改动的 key 的最小个数

可以配置多个条件,Redis 执行检查任务时,会遍历配置的条件数组,当检查同时满足 secondschanges 条件时,即触发 RDB 持久化的快照操作。

用法(redis.conf 中的注释):

# 将 DB(数据库)保存到磁盘
#
# save <seconds> <changes>
#
# 如果给定的秒数和对数据库执行的写入操作数同时发满足,Redis将保存数据库。
#
# 可以使用单个空字符串参数完全禁用快照,如下例所示:
#
# save ""
#
# 默认情况下,Redis将保存数据库:
#   * 距离上一次持久化已经 3600 秒(1小时),且至少有 1 个 key 发生了变化
#   * 距离上一次持久化已经 300 秒(5分钟),且至少有 100 个 key 发生了变化
#   * 距离上一次持久化已经 60 秒(1分钟),且至少有 10000 个 key 发生了变化
#
# 您可以通过取消注释以下三行来显式设置它们。
#
# save 3600 1
# save 300 100
# save 60 10000

# 快照保存的文件名称
dbfilename dump.rdb

# 工作目录
# DB 将写入到此目录中,使用上面的 `dbfilename` 指定的文件名
# AOF 文件也将在此目录中创建
# 请注意,您必须在此处指定目录,而不是文件名
dir ./

注意:如果没有配置 dbfilenamedir,RDB 持久化不会生效。

serverCron 定时检查

RedisServer 是存储 Redis 服务器资源的对象结构

RedisServer 维护着一堆代表 Redis 服务器的各种指标的变量,其中就包括用于检查 RDB 触发条件的信息:

  • lastsave:记录着上一次 RDB 持久化的时间
  • dirty:记录着有多少 key 发生变化
  • save_params:指向 redis.conf 中的 save 配置项

serverCron 是用于维护 RedisServer 的函数,Redis 通过定期调用 serverCron 函数更新 RedisServer 的各个指标来管理 Redis 服务器的资源。

serverCron 根据 redis.conf 中配置的频率运行,默认 hz 10,1秒调用 10 次,平均 100 毫秒一次。

serverCron 负责的工作很多,其中就包括检查 RDB 持久化操作的触发条件。

总的来说,RDB 自动触发是通过 Redis 定时运行 serverCron 函数检查 redis.conf 中的触发条件来实现的。

AOF 持久化( Append-only file)

快照功能并不是非常持久(durable)。如果运行 Redis 的计算机停止运行,电源出现故障,或者您意外的杀死实例(Linux 系统 kill -9 立即停止进程),那么服务器将丢失最近写入、且还未保存到快照中的数据。

尽管对于某些程序来说,数据的持久性并不是最重要的考虑因素,但对于那些追求完全持久化(full durability)的程序来说,快照功能就不太适用了。

从 1.1 版本开始,Redis 增加了一种可替代的、完全持久的方式:AOF 持久化。

AOF 可以将 Redis 执行的每一条写命令记录到操作日志,存储到硬盘文件中,重新启动 Redis 时,它将重新执行AOF 文件中的命令以达到恢复数据的目的。

记录日志的过程显然会降低 Redis 的性能,但是大部分情况下这个影响是可以接受的,另外使用较快硬盘可以提高 AOF 性能,

AOF 机制对于日志的写入操作采用的是 append 模式,就是追加模式,因此在写入过程中如果出现宕机问题,也不会破坏已经写入的日志数据。

AOF 配置

默认情况下,Redis 没有开启 AOF 方式的持久化,可以在配置文件中打开:

appendonly yes

# AOF 文件和 RDB 文件保存目录是一样的
dir ./

# AOF 文件名称
appendfilename "appendonly.aof"

AOF 同步策略

传统的 Linux 系统在内核设有缓冲区,大多数磁盘 I/O 都通过缓冲进行。当将数据写入文件时,内核通常先将该数据复制到缓冲区,然后由操作系统的调度机制决定何时将缓冲区内的数据同步到硬盘文件上,例如:缓冲区空间写满或达到特定的时间周期。这种输出方式被称为延迟写(delayed write)机制

延迟写减少了磁盘读写次数,但降低了文件内容的更新速度,在同步文件之前,如果系统故障宕机,缓冲区内的数据将丢失。

为了保证磁盘上实际文件系统与缓冲区中的内容的一致性,Linux 系统提供了 syncfsyncfdatasync 三个函数。

其中 fsync 函数针对单个文件操作,对其进行强制硬盘同步,fsync 将阻塞直到写入磁盘完成后返回,保证了数据持久化,常用于数据库这样的应用程序,这种应用程序需要确保将修改过的内容立即写到磁盘上。

AOF 记录命令的过程并不是直接(立即)将命令写入到日志文件中的,而是先追加到缓冲区,然后 AOF 根据对应的同步策略向硬盘进行同步操作(真正写入到文件)。

Redis 配置中的 appendfsync 用于设置 AOF 的同步策略,即调用 fsync 函数的不同时机,调用 fsync 周期越频繁,读写效率越差,但相应的安全性越高,发生宕机时丢失的数据越少。

AOF 有三种同步策略:

  • no:永远不要 fsync,由操作系统调度,默认情况下,Linux 每隔 30 秒撒互信一次数据。
  • always:每一次向 AOF 追加新命令时进行 fsync。非常慢,但最安全。
  • everysec(默认值):每秒进行一次 fsync。足够快,但如果发生意外(例如系统宕机),则可能会丢失 1 秒的数据。

一般情况下使用默认值 everysec 就足够了,既兼顾了性能又保证了安全。

AOF 文件分类

从 Redis 7.0.0 以来,Redis 使用了 multi part AOF 机制。也就是说,原始的单个 AOF 文件被分为 base 基础文件( 最多一个)和 incremental 增量文件(可能有多个):

  • base AOF:表示重写 AOF 时存在的数据的初始快照(RDB 或 AOF 格式)
  • incremental AOF:包含从创建最后一个 base AOF 以来的增量更改

所有这些文件都被放在单独的目录中,并由 manifest 清单文件清单跟踪。

AOF 日志重写

随着写操作的执行,AOF 会变得越来越大。例如如果将计数器递增 100 次,则数据集中只会有一个 key 包含最终值,但 AOF 中会记录 100 条命令。重建当前状态(还原原始数据)不需要其中的 99 条。

为了解决 AOF 文件体积膨胀的问题,Redis 提供了 AOF 文件重写(rewrite)机制,它是完全安全的。

当 Redis 继续向旧文件追加命令时,会基于创建当前数据集所需的最小操作集生成一个新的文件,一旦新文件准备就绪,Redis 将切换这两个文件,并开始向新文件追加命令。

AOF 文件重写不需要对现有的 AOF 文件进行任何读取、分析或者写入操作,而是通过读取服务器当前的数据库状态来实现。首先从数据库中读取键现有的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是 AOF 重写功能的实现原理。

AOF 日志重写使用与 RDB 快照相同的 copy-on-write 技巧:

  • 首先 fork 一个子进程
  • 子进程开始在临时文件中写入新的基础 AOF
  • 父进程打开一个新的增量 AOF 以继续写入更新。如果重写失败,旧的基础 AOF 和增量 AOF(如果有)加上新打开的增量 AOF 文件旧代表完整的更新数据集,因此重写是安全的。
  • 当子进程完成基础 AOF 的重写,父进程会收到一个信号,并使用新打开的增量 AOF 和子进程生成的基础 AOF 文件来构建临时清单,并将其持久化。
  • 现在 Redis 对清单文件进行原子交换,以便 AOF 重写的结果生效。Redis 还清理旧的基础文件和任何未使用的增量文件。

RDB vs AOF

RDB 优缺点

优点

  • RDB 是 Redis 数据的一种非常紧凑(compact)的单文件(single-file)时间点(point-in-time)表示,它保存了 Redis 在某个时间点上的数据集。RDB 文件非常适合备份(backup)。例如,你可能希望在最近的 24 小时内,每小时备份一次 RDB 文件,并在 30 内的每一天也保存一个 RDB 快照。这样的话,即使遇上故障,也可以随时将数据集还原到不同的版本。
  • RDB 非常适用于灾难恢复(disaster recovery),它是一个单一的压缩文件,可以(在加密后)将它传送到远程数据中心或 Amazon S3。
  • RDB 最大化了 Redis 的性能,因为 Redis 父进程在保存 RDB 文件时唯一要做的就是 fork(派生)一个子进程,然后子进程就会处理接下来的所有保存工作。父进程永远不用执行任何磁盘 I/O 或类似操作。
  • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快

缺点

  • 如果你需要尽量避免在服务器故障时(例如断电)丢失数据,那么 RDB 是不适合的。虽然 Redis 允许你设置不同的保存点(save points)来控制保存 RDB 文件的频率,但是,因为 RDB 文件需要保存整个数据集的状态,所以它并不是一个轻松的操作。我们通常会每隔 5 分钟或更长时间才创建一个 RDB 快照。在这种情况下,一旦 Redis 因任何原因未正确关闭而停止工作,就可能会丢失几分钟的数据。
  • 每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程。如果数据集很庞大,fork() 可能会非常耗时,如果数据集非常巨大,并且 CPU 时间非常紧张的话,则可能导致 Redis 停止处理客户端的请求几毫秒甚至 1 秒钟。虽然 AOF 重写也需要进行 fork() ,但无论 AOF 重写的执行间隔有多长,数据都是安全的,不会有任何损失。

AOF 优缺点

优点

  • 使用 AOF 持久化会让 Redis 变得更持久(much more durable):你可以设置不同的 fsync 策略,比如无 fsync,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,最多也只会丢失一秒钟的数据(fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。
  • AOF 文件是一个只进行追加操作的日志文件(append only log),因此在出现意外(例如断电)时不会出现查找或损坏问题。即使由于某种原因(磁盘已满或其它原因),日志包含了未写入完整的命令,redis-check-aof 工具也可以轻易地修复这种问题。
  • AOF 文件有序地保存了对数据库执行的所有写入操作,这些写入操作以易于理解和解析的 Redis 协议的格式保存。 你甚至可以轻松的导出 AOF 文件。例如,如果你不小心执行了 FLUSHALL 命令,只要在此期间没有对日志进行重写,就可以通过停止服务器、删除 AOF 文件末尾的 FLUSHALL 命令,并重启 Redis 来恢复数据集。

缺点

  • 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。在一般情况下,每秒 fsync 的性能依然非常高,而禁用 fsync 可以让 AOF 的速度和 RDB 一样快,即使在高负荷之下也是如此。尽管如此,在处理巨大的写入负载时,RDB 仍然可以提供更有保证的最大延迟时间(latency)。

总结

持久化方式优点缺点
RDB文件比 AOF 小
异步备份,性能好
恢复大数据集速度比 AOF 快
数据安全性低,无法做到实时持久,容易丢失数据
数据量比较大时备份速度慢
AOF数据安全性高,可以实现实时持久
有利于开发分析
相同数据集比 RDB 文件大
根据所使用的 fsync 策略,AOF 速度可能会慢于 RDB

一般情况下,如果你希望达到足以媲美 PostgreSQL 的数据安全性,则应该同时使用这两种持久性方法。

如果你非常关心你的数据,但在发生灾难时仍可以承受几分钟的数据丢失,那么你只需使用 RDB 即可。

有许多用户单独使用 AOF,但 Redis 不鼓励这样做,因为时不时地生成 RDB 快照非常便于进行数据库备份,并且在 Reids 重启时 RDB 恢复数据集的速度也要比 AOF 快。

注意:由于所有这些原因,Redis 可能会在将来将 AOF 和 RDB 统一到一个单一的持久性模型中(长期计划)。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值