浅谈redis持久化

在 Github 上修改

前言

前面我们讲了 Redis 的数据结构(Redis那些事之数据结构),今天我们来看看 Redis 的持久化,Redis 的持久化分两种 RDB 和 AOF。这两种各有优缺点,我们先看下官方是怎么描述这两种结构的:

RDB持久性以指定的时间间隔执行数据集的时间点快照。
AOF持久性记录服务器接收的每个写入操作,将在服务器启动时再次播放,重建原始数据集。 使用与Redis协议本身相同的格式以仅追加方式记录命令。 当Redis太大时,Redis能够重写日志背景。

我们可以选择关闭持久化,把 Redis 作为一个内存缓存使用,也可以开启持久化做数据库使用,RDB 和 AOF 可以同时开启,同时开启的情况下 Redis 优先读取 AOF 里面的数据。最重要的是理解 RDB 和 AOF 的区别和各自的优缺点,以便我们在不同的业务员场景下择优选择。

RDB

RDB 持久化可以手动执行,也可以根据配置选项定期执行,该功能可以将某个时间点的数据库状态保存到一个 RDB 文件中。因为 RDB 是保存在硬盘中,所以即使 Redis 服务器进程挂掉,只要 RDB 文件存在,Redis 就可以用它来还原数据状态。
Redis 提供两个手动执行命令 SAVE、BGSVE,SAVE命令执行时,客户端发送的所以命令请求都会被阻塞。BGSAVE 命令是由主进程 fork 出一个子进程进行持久化。所以在持久化的过程中 Redis 还可以继续执行客户端的命令,持久化由子进程执行。因为 BGSAVE 命令是非阻塞的,所以自动执行全部采用的是 BGSAVE 命令。
RDB 文件保存了用户的写入和删除命令,并根据不同的数据类型进行相应的编码,一个标准的 RDB 文件一般有一下部分组成:

  1. REDIS
  2. db_version RDB 文件版本号
  3. database 数据库
  4. EOF 结束标识符
  5. check_sum 校验和

其中 database 的格式为:

  1. SELECTDB 类似 flag 标识,当程序读到这儿的时候标识接下来读入的是一个数据库号码
  2. db_number 数据库号
  3. key_value_pairs 保存了数据库中所以的键值对数据、过期条件等

其中 key_value_pairs 部分的 key 是采用的 SDS 编码, value 是根据不同的数据类型进行存储(参考:Redis那些事之数据结构

AOF

除了 RDB 持久化功能之外 Redis 还提供了 AOF(append only file)持久化功能,AOF 是通过保存 Redis服务器所执行的写命令来记录数据库状态的。
AOF 的实现可以功能大体分为 命令追加(append)、文件写入、文件同步(sync)。
当 AOF 功能打开的时候,服务器在执行完一个写命令后,会以写一个是将被执行命令追加到服务器状态的 aof_buf 缓冲区的末尾。Redis 服务器在一个事件循环(loop)周期里它会调用一次 flushAppendOnlyFile 函数。考虑是否将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件里面。
因为 AOF 是通过客户端发送的写命令来保证数据库的状态的,所以随着时间的流失, AOF 文件中的内容可能会出现越来越多对同样一个键的修改。文件的体积也越来越大,如不加以控制,可能会对 Redis 服务器造成影响,使用 AOF 恢复所需的时间也会加大。 Redis 为此提供了 AOF 重写功能, AOF 的重写并不是对现有文件进行分析然后进行重写,而是遍历读取数据库里的数据,然后把对应的命令转成写入命令,写入到一个新的文件。这个执行过程同样是阻塞进行的,所以可以继续采用子进程来执行,等子进程处理完后对父进程发送一个信号通知重新执行完毕。然后父进程对原来的 AOF 文件原子性的覆盖。(在子进程执行重写的过程,父进程同样会接收命令,这个期间主进程所接收到的命令都会保存到缓冲区,在执行覆盖前,Redis服务会把缓冲区的命令追加到子进程发来的 AOF 文件里面)。

RDB 和 AOF 的优缺点

RDB 的优点

  • RDB 文件非常适合备份,比如可以根据时间或者是修改的次数,进行归档,然后在发生灾难的时候轻松的根据恢复不同的版本数据。
  • RDB 非常适合灾难恢复,可以将单个压缩文件传输到远端数据中心,也可以传输到 Amazon S3(可能是加密的)。
  • RDB 最大限度地提高了 Redis 的性能,因为 Redis 父进程为了持久化需要做的唯一工作就是分配一个将完成所有其余工作的孩子。 父实例永远不会执行磁盘 I/O 或类似操作。
  • 与 AOF 相比,RDB 允许使用大数据集更快地重启。

AOF 的优点

  • 使用 AOF Redis 更持久:你可以使用不同的 fsync 策略:根本没有 fsync,每秒 fsync,每次查询都有 fsync。使用 fsync 的默认策略,每秒写入性能仍然很好(使用后台线程执行 fsync,并且当没有 fsync 正在进行时,主线程将努力执行写入。)但是你只能丢失一秒的写入。
  • AOF 日志是仅附加日志,因此如果停电,则没有搜索,也没有损坏问题。即使由于某种原因(磁盘已满或其他原因)日志以半写命令结束,redis-check-aof 工具也能够轻松修复它。
  • 当 Redis 太大时,Redis 能够在后台自动重写 AOF。重写是完全安全的,因为当 Redis 继续附加到旧文件时,使用创建当前数据集所需的最小操作集生成一个全新的文件,并且一旦第二个文件准备就绪,Redis 会切换两个并开始附加到新的那一个。
  • AOF 以易于理解和解析的格式一个接一个地包含所有操作的日志。你甚至可以轻松导出 AOF 文件。例如,即使你使用 FLUSHALL 命令刷新了所有错误,如果在此期间未执行重写日志,你仍然可以保存数据集,只需停止服务器,删除最新命令,然后重新启动 Redis。

RDB 的缺点

  • 如果你需要在 Redis 挂掉后将数据的丢失性降到最小,那么 RDB 可能不合适。你可以根据配置文件设置不同的时间保存点,例如;对数据集进行至少 5 分钟和100次写入之后保存 RDB 文件,那么 5 分钟内或者修改次数不满足 100 次的数据可能就会丢失。
  • RDB 为了持久化会经常 fork 才能将子进程的数据持久储存在磁盘上,如果数据集很大, fork 可能会非常耗时,并且如果数据集非常大且 CPU 性能不佳,可能会导致 Redis 停止服务客户端几毫秒甚至一秒钟。 AOF 也需要 fork ,但你可以调整你想要重写日志的频率而不需要对持久性进行任何权衡。

AOF 的缺点

  • 因为 AOF 是保存的写入命令,所以同样数据下 AOF 一般比 RDB 文件更大。
  • 根据确切的 fsync 策略,AOF 可能比 RDB 慢。一般来说,fsync 设置为每秒性能仍然非常高,并且在 fsync 禁用的情况下,即使在高负载下也应该与 RDB 一样快。即使在写入负载很大的情况下,RDB 仍能够提供有关最大延迟的更多保证。