Redis 系列 3. 持久化机制:RDB、AOF 与混合持久化


1. Redis 为什么需要持久化

Redis 主要在内存中读写数据。如果只把它当纯缓存,进程重启后缓存丢失通常可以接受;但如果 Redis 中保存了排行榜、计数器、会话、消息流、库存扣减中间状态等数据,就要考虑重启后的恢复问题。

Redis 持久化主要有两种方式:

方式 核心思路 适合场景
RDB 按时间点生成内存快照 备份、全量恢复、对数据实时性要求不高
AOF 记录每次写命令,重启时重放 对数据丢失更敏感,希望恢复到更近时间点

可以先明确一个判断原则:如果 Redis 中只是缓存,持久化可以关闭;如果 Redis 中有业务状态,至少要开启 AOF everysec,并结合磁盘性能、fsync 策略和业务容忍度评估数据丢失窗口。

2. RDB 是什么

RDB,全称 Redis Database,是 Redis 在某个时间点生成的内存快照文件。

可以把 RDB 理解成“拍照”:Redis 在某个时刻把内存里的数据集保存成一个二进制文件,默认文件名通常是 dump.rdb。真正落地时,BGSAVE 的核心机制是 fork 子进程,并依赖操作系统的 copy-on-write 让子进程看到生成快照时的数据视图。

RDB快照

2.1 RDB 的特点

特点 说明
文件紧凑 RDB 是压缩后的二进制快照,适合备份和传输
恢复速度快 恢复时直接加载快照,比逐条命令重放更快
有时间窗口 两次快照之间如果 Redis 宕机,中间写入会丢失
fork 子进程 BGSAVE 会 fork 子进程做持久化,主进程继续服务
可能有额外内存压力 fork 后写时复制可能带来内存放大

3. RDB 如何触发

RDB 有自动触发和手动触发两类。

3.1 自动触发

配置文件中通过 save 规则控制:

save 3600 1
save 300 100
save 60 10000

含义是:

配置 说明
save 3600 1 3600 秒内至少 1 次修改则触发
save 300 100 300 秒内至少 100 次修改则触发
save 60 10000 60 秒内至少 10000 次修改则触发

注意:不同 Redis 版本默认 save 配置可能不同,实际以本机 redis.conf 为准。

多条 save 规则之间是 OR 关系,只要任意一条规则满足,就会触发一次后台快照。

3.2 手动触发

手动触发有两个命令:

save
bgsave

区别如下:

命令 说明 是否阻塞
SAVE 主进程直接执行 RDB 保存 会完全阻塞 Redis 主线程
BGSAVE fork 子进程执行 RDB 保存 主进程不长时间阻塞,但 fork 有瞬时开销
# 生产环境一般不要直接执行 SAVE,更常用 BGSAVE
127.0.0.1:6379> SAVE          # 手动执行 RDB 持久化,会阻塞 Redis 主线程,生产环境慎用
OK
127.0.0.1:6379> BGSAVE        # 后台异步执行 RDB 持久化,生产环境更常用
Background saving started
127.0.0.1:6379> LASTSAVE      # 查看最近一次 RDB 保存成功的 Unix 时间戳
(integer) 1727500200

# RDB 自动保存规则
# 表示 3600 秒内至少有 1 个 key 发生变化,就触发一次 RDB 保存
# 表示 300 秒内至少有 100 个 key 发生变化,就触发一次 RDB 保存
# 表示 60 秒内至少有 10000 个 key 发生变化,就触发一次 RDB 保存
save 3600 1 300 100 60 10000

# 自定义保存规则
# 表示 5 秒内至少有 2 个 key 发生变化,就触发一次 RDB 保存
save 5 2
# 注意:这里必须指定目录,而不是文件名
# RDB 文件保存目录
dir ./myredis/dumpfiles
# RDB 文件名
dbfilename dump6379.rdb

SAVE 会让 Redis 主线程直接做快照保存。在 Redis 单线程执行命令的模型下,这意味着保存期间其它客户端请求都无法被正常处理,所以生产环境通常不直接使用。

BGSAVE 的主要保存工作由子进程完成,但不能理解为完全没有影响。fork 本身会短暂阻塞主线程;如果实例内存很大,fork 延迟会变明显。fork 之后如果主进程持续写入大量数据,copy-on-write 会带来额外内存占用。

4. RDB 相关配置

常用配置项如下:

dir /myredis
dbfilename dump6379.rdb
rdbcompression yes
rdbchecksum yes
stop-writes-on-bgsave-error yes
save 3600 1 300 100 60 10000

参数说明:

参数 说明
dir RDB 文件所在目录
dbfilename RDB 文件名
rdbcompression 是否压缩 RDB 文件
rdbchecksum 是否开启校验
stop-writes-on-bgsave-error 后台保存失败后是否停止写入,用来避免“写入成功但无法持久化”的风险
save 自动快照触发规则

如果想关闭自动 RDB 快照:

save ""

也可以在线修改:

config set save ""

但在线修改只是当前实例生效,是否持久保存取决于后续是否执行 CONFIG REWRITE 以及配置文件权限,生产上更推荐直接改配置并走发布流程。

5. RDB 文件检查和恢复

检查 RDB 文件:

redis-check-rdb /myredis/dump6379.rdb

下面检查命令如下:

[root@hadoop100 ~]# cd /usr/local/bin/
[root@hadoop100 bin]# ll
总用量 21552
-rwxr-xr-x. 1 root root  5205192 928 13:10 redis-benchmark
lrwxrwxrwx. 1 root root       12 928 13:10 redis-check-aof -> redis-server
lrwxrwxrwx. 1 root root       12 928 13:10 redis-check-rdb -> redis-server
-rwxr-xr-x. 1 root root  5422600 928 13:10 redis-cli
lrwxrwxrwx. 1 root root       12 928 13:10 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 11436976 928 13:10 redis-server
[root@hadoop100 bin]# redis-check-rdb /myredis/dumpfiles/dump6379.rdb
[offset 0] Checking RDB file /myredis/dumpfiles/dump6379.rdb
[offset 27] AUX FIELD redis-ver = '7.0.11'
[offset 41] AUX FIELD redis-bits = '64'
[offset 53] AUX FIELD ctime = '1727500200'
[offset 68] AUX FIELD used-mem = '1029512'
[offset 80] AUX FIELD aof-base = '0'
[offset 89] Checksum OK
[offset 89] \o/ RDB looks OK! \o/
[info] 0 keys read
[info] 0 expires
[info] 0 already expired
[root@hadoop100 bin]#

恢复 RDB 的基本过程:

  1. 停止 Redis
  2. 将 RDB 文件放到 dir 指定目录
  3. 文件名改成 dbfilename 配置的名字
  4. 启动 Redis
  5. 使用 dbsize、业务 key、抽样查询验证恢复结果

示例:

redis-cli -p 6379 --pass 111111 shutdown
cp dump6379.rdb /myredis/dump6379.rdb
redis-server /myredis/redis7.conf
redis-cli -p 6379 --pass 111111 dbsize

实际恢复时,Redis 启动会自动在 dir 指定目录查找 dbfilename 对应的 RDB 文件并加载,不需要额外执行“恢复命令”。手动步骤的重点是把文件放到正确目录、使用正确文件名,并在启动后验证 key 数量和业务数据。

6. RDB 的优缺点

6.1 优点

  1. 文件紧凑,适合做周期性备份。
  2. 恢复速度快,适合大规模数据全量恢复。
  3. 对主进程影响相对较小,BGSAVE 由子进程完成主要工作。

6.2 缺点

  1. 两次快照之间的数据可能丢失。
  2. fork 时可能带来内存压力,copy-on-write 在高写入场景下可能让内存占用明显放大,极端情况下接近额外一份数据集。
  3. 快照很大时,磁盘 IO 会明显上升,也可能带来延迟抖动。

所以 RDB 更适合“允许丢一段时间窗口数据,但希望恢复快”的场景。

7. AOF 是什么

AOF,全称 Append Only File。它不是保存某个时刻的数据快照,而是把 Redis 执行过的写命令追加到日志文件中。Redis 重启时重新执行这些命令,从而恢复数据。

对比 RDB:

对比项 RDB AOF
记录内容 数据快照 写命令日志
恢复方式 加载快照 重放命令
文件大小 通常较小 通常较大,需要重写
数据丢失窗口 取决于快照间隔 取决于 fsync 策略
恢复速度 通常更快 命令多时更慢

7.1 AOF 持久化工作流程

AOF 的全称是 Append Only File,它会把 Redis 执行过的写命令追加保存到 AOF 文件中。Redis 重启时,可以通过重新执行 AOF 文件中的命令来恢复数据。

AOF 持久化的大致流程如下:

AOF 工作流程

步骤 说明
1 Client 作为命令的来源,会不断向 Redis Server 发送写命令。
2 写命令到达 Redis Server 后,并不是直接写入 AOF 文件,而是先写入 AOF 缓冲区。AOF 缓冲区是内存中的一片区域,用来临时保存写命令,避免每条命令都立即进行磁盘 IO。
3 Redis 会根据 AOF 缓冲区同步文件的写回策略,将缓冲区中的命令写入磁盘上的 AOF 文件。
4 随着 AOF 内容不断增加,AOF 文件会越来越大。为了避免文件膨胀,Redis 会根据规则进行命令合并,也就是 AOF 重写,从而达到压缩 AOF 文件的目的。
5 当 Redis Server 重启时,会从 AOF 文件 中重新加载数据,恢复 Redis 中的数据状态。

这里有两层缓冲要区分:第一层是 Redis 自己维护的 AOF buffer,第二层是操作系统的 page cache。Redis 把数据写给内核之后,并不等于数据已经落到物理磁盘,真正落盘还取决于 fsync 策略和操作系统调度。

简单来说,AOF 的流程可以理解为:

Client 写命令
    ↓
Redis Server 接收命令
    ↓
写入 AOF 缓冲区
    ↓
根据写回策略刷入 AOF 文件
    ↓
AOF 文件过大时触发 AOF 重写
    ↓
Redis 重启时加载 AOF 文件恢复数据

8. 开启 AOF

核心配置:

appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec

Redis 7 需要特别注意:AOF 默认采用 multi-part AOF 机制,不一定只看到一个单独的 appendonly.aof 文件。通常会在 appenddirname 指定目录下看到 manifest、base、incr 等文件。其中 manifest 是核心索引文件,用来记录当前有效的 base 文件和 incr 文件。

可以在数据目录下查看:

ls -lh /myredis/appendonlydir

如果使用 Redis 7,看到类似下面的文件是正常的:

appendonly.aof.manifest
appendonly.aof.1.base.rdb
appendonly.aof.1.incr.aof

其中 base.rdb 是重写时生成的全量基线文件,incr.aof 是基线之后继续追加的增量写命令。Redis 启动恢复时会根据 manifest 组合加载这些文件。这点和很多旧文章只讲单个 AOF 文件不同。

9. AOF 三种写回策略

AOF 写命令进入缓冲区后,需要通过 fsync 刷到磁盘。appendfsync 有三种策略:

策略 配置 说明
每条命令刷盘 appendfsync always 最安全,但性能损耗最大
每秒刷盘 appendfsync everysec 性能和可靠性折中,通常最多丢 1 秒级数据
交给系统决定 appendfsync no 性能好,但丢失窗口不可控

生产上最常见的是:

appendfsync everysec

这是 Redis 官方实践中很常见的折中选择。它不保证绝对零丢失,但性能和可靠性比较平衡。

需要注意,everysec 的“1 秒”是通常情况下的经验窗口,不是严格承诺。Linux 磁盘 flush、虚拟化存储、IO 拥塞或系统极端抖动,都可能让实际落盘延迟变大。生产环境要结合磁盘性能、监控指标和业务可接受丢失窗口评估,而不是只记“最多丢 1 秒”。

10. AOF 文件检查和修复

检查 AOF 前先看当前是不是 Redis 7 的 multi-part AOF。如果 appendonlydir 下存在 manifest 文件,先根据 manifest 和启动日志确认具体的 base、incr 文件,再检查对应文件;如果是旧版本或单文件 AOF,再检查具体的 AOF 文件。

# Redis 7 multi-part AOF,按实际文件名检查 incr 或 base 文件
redis-check-aof /myredis/appendonlydir/appendonly.aof.1.incr.aof

# 旧版或单文件 AOF
redis-check-aof /myredis/appendonly.aof

如果 AOF 尾部损坏,可以尝试修复。修复前必须先备份目录或文件:

cp -r /myredis/appendonlydir /myredis/appendonlydir.bak

然后按实际文件形态执行修复:

# Redis 7 multi-part AOF,按日志提示修复具体损坏的 AOF 文件
redis-check-aof --fix /myredis/appendonlydir/appendonly.aof.1.incr.aof

# 旧版或单文件 AOF
redis-check-aof --fix /myredis/appendonly.aof

如果 Redis 启动日志明确提示某个 AOF 文件损坏,则以日志中的文件路径为准。不要在没有备份的情况下直接执行 –fix。

常见 AOF 配置如下:

# 开启 AOF 持久化
# yes 表示开启,Redis 会把执行过的写命令追加保存到 AOF 文件中
appendonly yes
# AOF 写回策略:每次写命令都同步写入磁盘
# 数据安全性最高,但性能影响最大,生产环境一般不推荐
# appendfsync always
# AOF 写回策略:每秒写入一次磁盘
# 性能和数据安全比较均衡,生产环境常用配置
appendfsync everysec
# AOF 写回策略:由操作系统决定什么时候写入磁盘
# 性能最好,但宕机时可能丢失较多数据
# appendfsync no

11. AOF 重写机制

AOF 是追加日志,随着写入越来越多,文件会越来越大。比如对同一个 key 执行了 100 次 INCR,最终恢复数据时其实只需要最后的值,不需要完整保留中间 100 条命令。

AOF 重写就是把冗余命令压缩成恢复当前数据集所需的最小命令集合。重写由 BGREWRITEAOF fork 出的子进程完成,主线程仍然可以继续处理请求,但 fork、磁盘写入和后续文件切换都会带来额外 CPU、内存和 IO 压力。

手动触发:

bgrewriteaof

自动触发常用配置:

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

含义是:当 AOF 文件比上次重写后增长 100%,并且文件至少达到 64MB 时,触发重写。

# 几种类型文件的前缀,后跟有关序列和类型的附加信息
appendfilename "appendonly.aof"

# 新版本增加的目录配置项目
appenddirname "appendonlydir"

# 如果 appendonlydir 下存在 multi-part AOF,通常会看到下面几类文件:
1. 基础文件
   appendonly.aof.1.base.rdb
2. 增量文件
   appendonly.aof.1.incr.aof
   appendonly.aof.2.incr.aof
3. 清单文件
   appendonly.aof.manifest

重写后的结果通常是:

  1. 文件更小
  2. 重启恢复更快
  3. 冗余历史命令减少

所以 bgrewriteaof 不应理解成“完全无影响”。大实例或慢磁盘环境里,AOF rewrite 可能造成 IO 抢占和 latency spike。生产上要关注 INFO persistence、磁盘 util、fork 耗时和 Redis 延迟监控。

12. AOF 的优缺点

12.1 优点

  1. 数据丢失窗口更小。
  2. 日志追加,语义直观。
  3. everysec 策略在性能和可靠性之间比较平衡。

12.2 缺点

  1. 文件通常比 RDB 大。
  2. 恢复时需要重放命令,可能比 RDB 慢。
  3. AOF 写入、fsync 和 rewrite 会带来额外 IO,并可能造成延迟抖动。
  4. 如果不了解 Redis 7 multi-part AOF,排查文件时容易误判。

13. RDB 和 AOF 同时开启

Redis 可以同时开启 RDB 和 AOF。

配置示例:

save 3600 1 300 100 60 10000
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes

当 RDB 和 AOF 同时存在时,Redis 重启恢复通常会优先使用 AOF,因为 AOF 往往包含更完整的数据变化。

aof-use-rdb-preamble yes 表示 AOF 重写时使用 RDB 格式作为 AOF 文件的前半部分,再追加增量 AOF 内容。这就是 RDB + AOF 的混合格式。它的核心收益是提升恢复速度:启动时先快速加载 RDB 基线,再重放较短的增量 AOF。

配置指令 配置含义 配置示例
appendonly 是否开启 AOF appendonly yes
appendfilename AOF 文件名称 appendfilename “appendonly.aof”
appendfsync AOF 同步方式 everysec / always / no
no-appendfsync-on-rewrite AOF 重写期间是否同步 no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage AOF 自动重写触发比例 auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size AOF 自动重写触发的最小文件大小 auto-aof-rewrite-min-size 64mb

14. 如何选择持久化方案

可以按下面这张表判断。

场景 推荐方式 原因
纯缓存,数据可从数据库重建 关闭持久化或只保留 RDB 重启后重新预热即可
普通业务缓存,希望重启恢复快 RDB 文件小,恢复快
计数、排行、状态等不希望丢太多 AOF everysec 通常是秒级丢失窗口,但要结合磁盘和 fsync 状态评估
希望兼顾恢复速度和较小丢失窗口 AOF + 混合持久化 重写后前半段是 RDB,后半段是增量 AOF
极端要求零丢失 Redis 不应作为唯一存储 即使 always 也要考虑系统、磁盘、复制链路和业务事务

我个人更常用的组合是:

appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
save 3600 1 300 100 60 10000

但最终要看业务是否允许丢失、磁盘性能和恢复时间要求。纯 cache、业务 state、轻量 queue 的持久化策略不应该完全相同:缓存更看重恢复速度和预热能力,状态数据更看重丢失窗口,队列类数据还要评估 ACK、重复消费和业务补偿。

本质上,持久化选择是在恢复速度、数据完整性、CPU/fork 成本和磁盘 IO 之间做权衡。RDB 更偏 CPU/fork 和快照备份,AOF 更偏持续 IO 和更小丢失窗口,混合持久化则试图在恢复速度和完整性之间取中间值。

15. 纯缓存模式

如果 Redis 明确只做缓存,不需要落盘,可以关闭 RDB 和 AOF:

save ""
appendonly no
纯缓存模式

这种方式重启最快,也避免了持久化 IO,但代价是 Redis 重启后数据全部丢失。

16. 排查持久化问题的常用命令

实际排查时常用这些命令:

# 查看持久化相关信息
info persistence

# 查看配置
config get save
config get appendonly
config get appendfsync
config get dir
config get dbfilename
config get appendfilename
config get appenddirname

# 手动触发
bgsave
bgrewriteaof

# 检查文件
redis-check-rdb /myredis/dump6379.rdb
redis-check-aof /myredis/appendonlydir/appendonly.aof.1.incr.aof

INFO persistence 里重点看:

字段 说明
rdb_last_bgsave_status 最近一次 RDB 是否成功
rdb_last_save_time 最近一次 RDB 保存时间
aof_enabled AOF 是否开启
aof_last_bgrewrite_status 最近一次 AOF 重写是否成功
aof_current_size 当前 AOF 大小
aof_base_size 上次重写后的 AOF 基准大小

17. 本文小结

Redis 持久化不要只记“RDB 快、AOF 安全”这种口号,要看数据丢失窗口、恢复速度、fork/COW 内存压力、磁盘 IO 和运维复杂度。

核心结论如下:

  1. RDB 是快照,适合备份和快速恢复,但可能丢失两次快照之间的数据。
  2. AOF 是写命令日志,everysec 是常见折中,通常是秒级丢失窗口,但极端 IO 抖动下可能更大。
  3. Redis 7 的 AOF 可能是 multi-part AOF,要根据 manifest 找 base 和 incr 文件,不要只找一个单独的 appendonly.aof。
  4. 混合持久化通过 aof-use-rdb-preamble yes 使用 RDB 基线加增量 AOF,核心收益是提高恢复速度。
  5. 如果 Redis 只是缓存,可以关闭持久化;如果 Redis 保存业务状态,必须明确最多能接受丢多少数据。

下一篇继续看 Redis 单机能力:事务、Pipeline 和发布订阅。


文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录