Redis 数据持久化
Redis 中,有两种方式将数据持久化到磁盘。一种称之为快照 (Spapshotting), 将某一时刻存在数据写道磁盘。另外一种称之为AOF 仅追加文件 (append-only file), 它是将到来的所有写命令写到磁盘上。这两种方式可以一起使用,也可以单独使用,或者不适用持久化。
选择配置数据持久话的原因还是为了在 Redis,Redis 所在的主机硬件等发生故障时进行恢复,可以将持久化的文件在远程主机进行备份,故障时进行恢复。而且,如果 Redis 中的数据时大数据集上的聚合分析结果,没有备份,重新计算的代价可能时无法接受的。
通过快照将数据持久化到磁盘
在 Redis 中,可以通过创建一个快照,创建一个内部中数据的某个时刻的副本,这些副本可以被备份,复制到其它服务器,创建一个 Redis 服务器的副本,或者留着待以后重启使用。
基本的配置选项
1 | save 60 1000 # 创建快照的频率。如果自上一次创建快照后的 60s 内有 1000 此写,就开启新的快照 |
自上一次快照完成后,直到下一次快照开始执行,这个期间,如果 Redis 崩溃,系统或硬件故障,期间的写数据就会丢失。
五种初始化快照的方法
任何的 Redis 客户端都可以通过调用
BGSAVE
命令来初始化快照(创建快照)。在所有支持BGSAVE
的平台上,Redis 会进行进程的 fork, 子进程会将快照写到磁盘,而父进程仍然可以用于响应来自客户端的命令。当一个进程 fork 时,底层的操作系统会创建该进程的一个副本。在 Unix 和类 Unix 的系统上,复制进程会被优化:最开始,子进程和父进程时共享所有内存的。当父进程或子进程开始写内存,内存将不再共享。
Redis 的客户端可以通过调用
SAVE
命令来初始化快照,这将导致 Redis 停止对任何命令的响应,直到快照完成。不经常使用,但是如果对于该这种等待 ok 或者没有足够的内存执行BGSAVE
操作,可以使用。如果 Redis 配置了
save
选项,如save 60 10000
, 如果自上一次快照成功后的 60s 内,已经有 10000 个写操作,那么 Redis 会自动触发一个BGSAVE
操作。可以配置多个save
行,任意一条规则满足,就会触发BGSAVE
操作。当 Redis 接受到
SHUTDOWN
终止命令时,或者接受到标准的TERM
信号,Redis 会执行SAVE
操作,阻塞任何客户端执行任何命令,然后再终止。当一个 Redis 服务器连接到另一个 Reids 服务器,并且发起了
SYNC
同步命令开始复制(replication), Master Redis 服务器将会开始一个BGSAVE
操作,如果当前没有一个正在进行中的BGSAVE
操作或者最近完成了。
只追加写文件持久化 (Append-only file persistence)
只追加写文件通过将修改写到文件的末尾,保存了数据发生修改时的记录。这样,任何人都有可以通过从头到尾,重放 (replay) 只追加写日志文件就可以恢复整个数据集。可以通过设置配置项 appendonly yes
开启。
文件同步
当写文件到磁盘上时,至少发生了三件事:首先是写缓存,当调用 file.write()
或其它语言中等价的命令时会执行该操作。当数据存在缓冲区中时,操作系统可以将这些数据再未来的某个时刻写到磁盘。可以通过调用 file.flush()
, 要求操作系统将数据写到磁盘上,但这只是发给操作系统的一个请求,并不会立即执行。由于数据实际时不在磁盘上的直到操作系统将它写到磁盘上,我们可以告诉操作系统同步文件到磁盘上,这将导致阻塞 (block),直到同步完成。当同步完成时,我们可以确定数据此时是在磁盘上的,并且如果系统故障,可以稍后读取进行恢复。
appendfsync always
如果设置了 appendfsync always
, Redis 的每次写将会导致一个磁盘的写过程,如果 Reid 崩溃了,这可以极大地减少数据丢失。然而,因为每次都有写磁盘这个过程,整体的性能会受限于此磁盘的性能。
appendfsync eversec
作为保持数据安全和保持高写入性能之间的合理折衷,我们还可以设置 appendfsync everysec。 此配置将每秒同步一次仅追加日志文件。 对于大多数常见用途,与不使用任何类型的持久性相比,我们可能不会发现每秒同步到磁盘的显着性能损失。 通过每秒同步到磁盘,如果系统崩溃,我们最多可能会丢失一秒钟已在 Redis 中写入或更新的数据。 此外,在磁盘无法跟上正在发生的写入量的情况下,Redis 会优雅地减速以适应驱动器的最大写入速率。
appendfsync no
Redis 并不会显示地执行任何文件同步,而是将这一切交给操作系统。这种情况下应该没有性能损失,但如果系统以某种方式崩溃,我们将丢失未知和不可预测的数据量。 如果我们使用的硬盘驱动器对于我们的写入负载来说不够快,Redis 会运行良好,直到将数据写入磁盘的缓冲区被填满,此时 Redis 会因为被阻止写入而变得非常慢。 通常不鼓励使用此配置选项。
重写/压缩 AOF
AOF 看起来比较完美,即能将数据损失降低到 1s,又可以最小化数据持久化到磁盘上地时间。但是问题是,Redis 的每次写命令,都会生成一条日志记录,随着时间的推移,AOF 日志文件的大小会不断增长,可能会导致磁盘空间耗尽。但更常见的问题是,在 Redis 重启时,由于需要按顺序执行 AOF 中的每条命令,处理较大的文件,需要花费更长的时间
此时可以使用 BGREWRITEAOF
, 它会通过移除冗余的命令,来尽可能地使得 AOF 变得更小一点。和 BGSAVE
命令一样,这个命令也会执行一次 fork 过程,由子进程完成 AOF 的重写,所以关于 fork 的时间,内存使用的问题,同样也适用于 BGREWRITEAOF
。而且更糟的时,当 AOF 被重写,操作系统需要删除几十 G 的 AOF 文件时,会使的操作系统中断几秒。
当启用 AOF , 并且满足以下两个配置项时,Redis 会启动一次 BGREWRITEAOF
, 如果 AOF 重写的频率过高,可以适当增加 auto-aof-rewritepercentage
, 但是可能会导致 Redis 启动需要花费更多的时间
1 | # 当 AOF 至少比 Redis 上次完成重写时的 AOF 大 100% 时 |