Redis 快照持久化学习笔记

Redis 是一种内存数据库,它将数据存储在内存中,所以如果不将数据保存到硬盘中,那么一旦 Redis 进程退出,保存在内存中的数据将会丢失。为此,Redis 提供了两种不同的持久化方法来将数据存储到硬盘里面。一种方法叫做快照(snapshotting),它可以将存在于某一时刻的所有数据写入硬盘里面。另一种方法叫 AOF(append-only file),它会在执行写命令时,将被执行的写命令复制到硬盘里面。这种两持久化方法既可以同时使用,也可以单独使用,当然如果 Redis 单纯只作为缓存系统使用的话,也可以两种持久化方法都不使用。具体选择哪种持久化方法取决于用户的应用场景。
快照持久化方法是 Redis 默认开启的持久化方法,本文介绍快照持久化方法,AOF 方法将在另一篇文章中介绍。

RDB 文件

Redis 将某一时刻的快照保存成一种称为 RDB 格式的文件中。RDB 文件是一个经过压缩的二进制文件,通过该文件,Redis 可以将内存中的数据恢复成某一时刻的状态。Redis 与 RDB 文件的关系可以通过下图 1 和图 2 来表示。


图 1:Redis 将内存的数据保存为 RDB 文件


图2:Redis 用 RDB 文件还原内存数据

SAVE 命令

Redis 提供了两个命令用来生成 RDB 文件,一个是 SAVE,一个是 BGSAVE。
SAVE 命令会阻塞 Redis 服务器进程,走到 RDB 文件创建完毕为止,在 Redis 服务器进程阻塞期间,Redis 不能处理任何命令请求。

1
2
redis 127.0.0.1:6379> save
OK

在生产环境,我们一般不会直接使用 SAVE 命令,原因是由于它会阻塞 Redis 进程。但是,如果机器已没有足够的内存去执行 BGSAVE 命令,或者即使等待持久化操作完毕也无所谓,我们也可以使用 SAVE 命令来生成 RDB 文件。

BGSAVE 命令

BGSAVE 命令会派生出一个子进程,然后由子进程创建 RDB 文件,因此,BGSAVE 命令不会阻塞 Redis 服务器进程。

1
2
redis 127.0.0.1:6379> bgsave
Background saving started

可以使用 LASTSAVE 命令来检查保存 RDB 文件的操作是否执行成功。

自动保存 RDB 文件

除了手动执行 SAVE 和 BGSAVE 命令来生成 RDB 文件外,Redis 还提供了自动保存 RDB 文件的功能。由于 BGSAVE 命令可以在不阻塞服务器进程的情况下执行,所以 Redis 允许用户通过设置配置来让 Redis 服务器每隔一段时间自动执行一次 BGSAVE 命令。
下面是 Redis 配置文件 redis.conf 中有关自动保存 RDB 文件的有关配置内容:

1
2
3
save 900 1
save 300 10
save 60 10000

上面配置的含义是,Redis 服务器只要满足以下三个条件中的任意一个, BGSAVE 命令就会被执行:

  • Redis 服务器在 900 秒之内,对数据库进行了至少一次修改
  • Redis 服务器在 300 秒之内,对数据库进行了至少 10 次修改
  • Redis 服务器在 60 秒之内,对数据库进行了至少 10000 次修改

涉及 RDB 文件的配置选项还包括:

1
2
3
4
5
dbfilename dump.rdb
dir ./
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
  • dbfilename:配置 RDB 文件名称
  • dir:配置 RDB 文件存放的路径
  • stop-writes-on-bgsave-error:当生成 RDB 文件出错时是否继续处理 Redis 写命令,默认为不处理
  • rdbcompression:是否对 RDB 文件进行压缩
  • rdbchecksum:是否对 RDB 文件进行校验和校验

快照持久化的优点

快照持久化的方法采用创建一个子进程的方法来将 Redis 的内存数据保存到硬盘中,因此,它并不会对 Redis 服务器性能造成多大的影响,这可以说是快照持久化方法最大的一个优点。
快照持久化使用的 RDB 文件是一种经过压缩的二进制文件,可以方便地在网络中传输与保存。通过恰当的配置,可以让我们方便快捷地将 Redis 内存数据恢复到某一历史状态。这对于提高数据的安全性,应对服务器宕机等意外的发生很有帮助。

快照持久化的缺点

尽管快照持久化允许 Redis 恢复到快照文件的状态,但如果 RDB 文件生成后,Redis 服务器继续处理了写命令导致 Redis 内存数据有更新,这时恰好 Redis 崩溃了而来不及保存新的 RDB 文件,那么 Redis 将会丢失这部分新的数据。也就是说,如果系统真的发生崩溃,那么我们将会丢失最近一次生成 RDB 文件之后更改的所有数据。因此,快照持久化方法只适用于那些即使丢失一部分数据也不会造成问题的应用场景。
另外,快照持久化方法需要调用fork()方法创建子进程。当 Redis 内存的数据量较大时,创建子进程和生成 RDB 文件得占用较多的系统资源和处理时间,这会对 Redis 正常处理客户端命令的性能造成较大的影响。
当然,如果我们可以妥善处理快照持久化方法可能带来的数据丢失,那么快照持久化仍然是一个不错的选择。

参考资料

  1. Redis 实战,Josiah L. Carlson 著,黄健宏译,人民邮电出版社,2015年
  2. Redis 设计与实现,黄健宏著,机械工业出版社,2015年
  3. https://redis.io/topics/persistence
  4. https://redis.io/commands/save
  5. https://redis.io/commands/bgsave
  6. Redis RDB 文件格式介绍,https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format
  7. Redis RDB 版本的历史,https://github.com/sripathikrishnan/redis-rdb-tools/blob/master/docs/RDB_Version_History.textile