Redis 提供了两种数据持久化的方式,一种是 RDB,另一种是 AOF。默认情况下,Redis 使用的是 RDB 持久化。
RDB 持久化
当 Redis 执行 RDB 持久化时,它会怎么做呢?
- Redis 进程会 fork 出一个子进程。
- 由子进程将内存中的所有数据写入到一个临时的 RDB 文件中。
- 完成写入操作之后,旧的 RDB 文件会被新的 RDB 文件替换掉。
下面是一些和 RDB 持久化相关的配置:
save 60 10000
:如果在 60 秒内有 10000 个 key 发生改变,那就执行 RDB 持久化。stop-writes-on-bgsave-error yes
:如果 Redis 执行 RDB 持久化失败(常见于操作系统内存不足),那么 Redis 将不再接受 client 写入数据的请求。rdbcompression yes
:当生成 RDB 文件时,同时进行压缩。dbfilename dump.rdb
:将 RDB 文件命名为 dump.rdb。dir /var/lib/redis
:将 RDB 文件保存在/var/lib/redis
目录下。
当然在实践中,我们通常会将stop-writes-on-bgsave-error
设置为false
,同时让监控系统在 Redis 执行 RDB 持久化失败时发送告警,以便人工介入解决,而不是粗暴地拒绝 client 的写入请求。
在考虑是否采用 RDB 持久化之前,要先了解 RDB 持久化的缺点:
- 在 Linux 系统中,fork 会拷贝进程的 page table。随着进程占用的内存越大,进程的 page table 也会越大,那么 fork 也会占用更多的时间。 如果 Redis 占用的内存很大 (例如 20 GB),那么在 fork 子进程时,会出现明显的停顿现象(无法处理 client 的请求)。另外,在不同机器上,fork 的性能是不同的,可以参见 Fork time in different systems。
- Linux fork 子进程采用的是 copy-on-write 的方式。在 Redis 执行 RDB 持久化期间,如果 client 写入数据很频繁,那么将增加 Redis 占用的内存,最坏情况下,内存的占用将达到原先的两倍。
- 如果业务场景很看重数据的持久性 (durability),那么不应该采用 RDB 持久化。譬如说,如果 Redis 每 5 分钟执行一次 RDB 持久化,要是 Redis 意外奔溃了,那么最多会丢失 5 分钟的数据。
AOF 持久化
可以使用appendonly yes
配置项来开启 AOF 持久化。Redis 执行 AOF 持久化时,会将接收到的写命令追加到 AOF 文件的末尾,因此 Redis 只要对 AOF 文件中的命令进行回放,就可以将数据库还原到原先的状态。
与 RDB 持久化相比,AOF 持久化的一个明显优势就是,它可以提高数据的持久性 (durability)。因为在 AOF 模式下,Redis 每次接收到 client 的写命令,就会将命令write()
到 AOF 文件末尾。
然而,在 Linux 中,将数据write()
到文件后,数据并不会立即刷新到磁盘,而会先暂存在 OS 的文件系统缓冲区。在合适的时机,OS 才会将缓冲区的数据刷新到磁盘(如果需要将文件内容刷新到磁盘,可以调用fsync()
或fdatasync()
)。
通过appendfsync
配置项,可以控制 Redis 将命令同步到磁盘的频率:
always
:每次 Redis 将命令write()
到 AOF 文件时,都会调用fsync()
,将命令刷新到磁盘。这可以保证最好的数据持久性,但却会给系统带来极大的开销。no
:Redis 只将命令write()
到 AOF 文件。这会让 OS 决定何时将命令刷新到磁盘。everysec
:除了将命令write()
到 AOF 文件,Redis 还会每秒执行一次fsync()
。在实践中,推荐使用这种设置,一定程度上可以保证数据持久性,又不会明显降低 Redis 性能。
然而,AOF 持久化并不是没有缺点的:Redis 会不断将接收到的写命令追加到 AOF 文件中,导致 AOF 文件越来越大。过大的 AOF 文件会消耗磁盘空间,并且导致 Redis 重启时更加缓慢。为了解决这个问题,在适当情况下,Redis 会对 AOF 文件进行重写,去除文件中冗余的命令,以减小 AOF 文件的体积。在重写 AOF 文件期间, Redis 会启动一个子进程,由子进程负责对 AOF 文件进行重写。
可以通过下面两个配置项,控制 Redis 重写 AOF 文件的频率:
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage 100
上面两个配置的作用:当 AOF 文件的体积大于 64MB,并且 AOF 文件的体积比上一次重写之后的体积大了至少一倍,那么 Redis 就会执行 AOF 重写。