Redis数据持久化设计:RDB 与 AOF

Tags
文件系统
快照设计
数据冗余
Redis
日志设计
CreatedTime
Aug 24, 2022 03:37 PM
Slug
UpdatedTime
Last updated August 24, 2022

概述

Redis 支持两种方式的持久化,一种是 RDB 方式,另一种是 AOF 方式。
前者会根据指定的规则“定时”将内存中的数据存储在硬盘上,而后者在每次执行命令后将命令本身记录下来。
两种持久化方式可以单独使用其中一种,但更多情况下是将二者结合使用。

RDB 持久化

什么是 RDB 持久化?

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

哪些情况下,redis 对数据进行快照?

1、根据配置规则进行自动快照
进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间窗口 M 和改动的键的个数 N。
含义是:每当时间 M 内被更改的键的个数大于 N 时,则生成快照
2、用户执行 SAVE 或 BGSAVE 命令
在 redis 中执行 save 命令,会阻塞客户端请求,如果数据较多,会导致 redis 不响应。
与之相反,BGSAVE 是异步的。
3、执行 FLUSHALL 命令
此命令会清空数据,如果此时有定义自动快照条件,那么会进行生成快照。
4、执行复制(replication)时
redis 集群中,在复制初始化进行时,会进行自动快照。

redis 快照原理

Redis 默认会将快照文件存储在 Redis 当前进程的工作目录中的 dump.rdb 文件中。
过程:
  1. Redis 使用 fork 函数复制一份当前进程(父进程)的副本(子进程)
  1. 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件
  1. 当子进程写入完所有数据后会用该临时文件替换旧的 RDB 文件,至此一次快照操作完成
这里操作系统的进程在进行 fork 时,用到了写时复制(copy-on-write)策略,即 fork 函数发生的一刻父子进程共享同一内存数据,所以新的 RDB 文件存储的是执行 fork 一刻的内存数据
写时复制策略也保证了在 fork 的时刻虽然看上去生成了两份内存副本,但实际上内存的占用量并不会增加一倍

异常情况

通过 RDB 方式实现持久化,一旦 Redis 异常退出,就会丢失最后一次快照以后更改的所有数据。
根据具体业务场景进行处理,不一定要求完美。例如,使用 Redis 存储缓存数据时,丢失最近几秒的数据或者丢失最近更新的几十个键并不会有很大的影响。如果数据相对重要,希望将损失降到最小,则可以使用 AOF 方式进行持久化。

AOF 持久化

什么是 AOF 持久化?

场景:当使用 Redis 存储非临时数据时,一般需要打开 AOF 持久化来降低进程中止导致的数据丢失。这类场景对数据完整性要求较高
具体实现:AOF 在每次执行命令后将命令本身记录下来(写操作相关的命令),之后按照命令重新执行一遍,就能恢复数据。

如何使用 AOF?

默认 redis 不开启,可以通过 appendonly 参数启用:appendonly yes
AOF 文件的保存位置和 RDB 文件的位置相同,默认是:appendonly.aof

如何优化 AOF?

AOF 重写机制

如果命令过多,AOF 文件中内容就会过多。比如对一个键的值连续修改多次,实际上生效的只有最后一次。
那么 AOF 文件中,只保留最后一条命令即可。可以通过修改配置文件来实现,这个操作就是:AOF 的重写。

同步执行写入

事实上,由于操作系统的缓存机制,在默认情况下系统每 30 秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘,在这 30 秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。
如果在写入 AOF 文件时,发生了此种丢失,就会造成数据丢失或错乱。
默认情况下 Redis 采用 everysec 规则,即每秒执行一次同步操作。always 表示每次执行写入都会执行同步,这是最安全也是最慢的方式。no 表示不主动进行同步操作,而是完全交由操作系统来做(即每 30 秒一次),这是最快但最不安全的方式。
通过参数配置开启:
# appendfsync always appendfsync everysec # appendfsync no