【Redis合集-05】Redis 持久化机制深度解析:RDB、AOF 与混合持久化

目录

1. Redis 持久化的两种思路

2. RDB 快照持久化

2.1 RDB 是什么

2.2 RDB 的触发方式

方式一:手动触发

方式二:自动触发(配置 save 参数)

方式三:通过 LASTSAVE 查看上次保存时间

2.3 BGSAVE 的底层原理:Copy-On-Write

2.4 RDB 文件的修复与检查

2.5 RDB 的优缺点

3. AOF 日志持久化

3.1 AOF 是什么

3.2 AOF 的三种写入策略

3.3 AOF 重写(Rewrite)

3.4 AOF 文件修复

3.5 AOF 的优缺点

4. 混合持久化(RDB-AOF Hybrid)

4.1 混合持久化解决什么问题

4.2 开启混合持久化

5. RDB 和 AOF 的选择与组合

5.1 生产环境的配置建议

5.2 同时开启 RDB 和 AOF 时的恢复逻辑

5.3 数据恢复流程

6. 持久化相关的性能优化

6.1 fork 引起的阻塞

6.2 AOF 刷盘策略的选择

6.3 多核 CPU 的利用

7. 运维实践中的注意事项

7.1 定期备份 RDB 文件

7.2 AOF 文件大小监控

7.3 主从架构下的持久化

7.4 避免持久化引起的性能抖动

8. 总结

Redis 作为内存数据库,数据都放在内存里。一旦进程退出或服务器宕机,内存数据就全没了。所以持久化是 Redis 数据安全的第一道防线,也是面试和实际运维中都绕不开的核心话题。

1. Redis 持久化的两种思路

Redis 提供了两种完全不同的持久化方式:

  • RDB(Redis Database):快照,把某个时间点的内存数据直接写到磁盘文件里。

  • AOF(Append Only File):日志,记录每一次写命令,重启时重放这些命令来恢复数据。

两种方式可以单独使用,也可以同时开启。

2. RDB 快照持久化

2.1 RDB 是什么

RDB 就是把 Redis 某一时刻的全量内存数据保存到一个二进制文件(默认叫 dump.rdb)中。

可以想象成给 Redis 的内存拍了一张照片,这张照片记录了拍照那一刻的所有数据。如果 Redis 挂了,用这张照片就能恢复到拍照时的状态。

2.2 RDB 的触发方式

方式一:手动触发
# 同步阻塞保存,主线程执行,保存期间不处理任何请求
SAVE

# 异步后台保存,fork 子进程执行,主线程继续处理请求
BGSAVE
  • SAVE:生产中禁用。它会在主线程中执行,如果数据量大,会阻塞所有客户端请求长达数秒甚至更久。

  • BGSAVE:推荐使用。Redis 会 fork 一个子进程,子进程负责把数据写入磁盘,主进程继续处理请求。

方式二:自动触发(配置 save 参数)
# redis.conf 中的配置(默认值)
save 900 1       # 900 秒内至少 1 次修改,触发 BGSAVE
save 300 10      # 300 秒内至少 10 次修改,触发 BGSAVE
save 60 10000    # 60 秒内至少 10000 次修改,触发 BGSAVE

多条 save 规则只要满足任意一条,就会自动触发一次 BGSAVE。这个机制非常实用,我们不需要手动执行备份,系统会根据数据变化频率自动保存。

如果不需要自动 RDB,可以注释掉所有 save 行,或者写 save ""

方式三:通过 LASTSAVE 查看上次保存时间
# 查看上次 BGSAVE 成功执行的时间戳
LASTSAVE

返回值是一个 Unix 时间戳,可以转换为可读时间。运维时可以用它来判断备份是否按时执行。

2.3 BGSAVE 的底层原理:Copy-On-Write

BGSAVE 之所以能在备份的同时不阻塞读写,靠的是操作系统提供的写时复制(Copy-On-Write,COW)机制。

执行流程如下:

  1. Redis 主进程调用 fork() 创建一个子进程。

  2. 刚 fork 完的那一刻,父子进程共享同一块物理内存(内存页表相同)。

  3. 子进程开始遍历内存数据,写入 RDB 文件。

  4. 在此期间,如果主进程需要修改某个数据(比如 SET),操作系统会把包含该数据的内存页复制一份,主进程在新页面上修改,子进程继续读旧页面。

  5. 子进程完成写入后退出,RDB 文件生成完毕。

整个过程,主进程基本不受影响,只是 fork 那一瞬间需要短暂停顿。

重点理解fork() 的速度和 Redis 实例的内存大小直接相关。内存越大,页表越大,fork 越慢。对于几十 GB 的大实例,fork 可能耗时几百毫秒甚至上秒,这期间主线程是阻塞的。

2.4 RDB 文件的修复与检查

# 检查 RDB 文件是否有损坏
redis-check-rdb dump.rdb

# 如果损坏,可以尝试修复(会丢弃无法修复的数据)
redis-check-rdb --fix dump.rdb

2.5 RDB 的优缺点

优点:

  • RDB 是单一紧凑的二进制文件,非常适合做冷备份。每天生成一份 dump.rdb,压缩后存到对象存储或异地机房,出问题时直接拿它恢复。

  • 恢复速度快。直接加载一个 RDB 文件,比逐条重放 AOF 日志快得多。

  • 子进程写入,主进程几乎不受影响。

缺点:

  • 两次快照之间的数据会丢失。如果 5 分钟保存一次,最坏情况就是丢 5 分钟的数据。

  • fork 子进程在内存大的时候耗时较长,会有短暂的阻塞。

3. AOF 日志持久化

3.1 AOF 是什么

AOF(Append Only File)记录的是每次写命令,追加到文件末尾。Redis 重启时,通过逐条重放 AOF 文件中的命令来恢复数据。

这就像 MySQL 的 binlog,记录了所有修改数据的操作。

3.2 AOF 的三种写入策略

AOF 的写入策略决定了性能和数据安全性之间的平衡。配置参数为 appendfsync

# redis.conf
appendfsync always     # 每个写命令都刷盘,最安全也最慢
appendfsync everysec   # 每秒刷盘一次,折中方案(默认)
appendfsync no         # 不主动刷盘,交给操作系统决定

三种策略对比:

策略原理数据安全性性能
always每个写命令完成后立即调用 fsync 刷盘最高,不丢数据最差
everysec每秒执行一次 fsync,异步线程负责最多丢 1 秒数据折中
no不调用 fsync,由操作系统决定何时刷盘(通常 30s)最差,可能丢大量数据最高

推荐使用 everysec,它是性能和安全性的最佳平衡。绝大部分业务场景下,丢 1 秒的数据是可以接受的。

3.3 AOF 重写(Rewrite)

AOF 文件会随着时间不断变大。比如对一个计数器反复执行 100 次 INCR,AOF 里就记录了 100 条命令,但恢复时只需要知道最终值就行。

AOF 重写就是把 AOF 文件压缩的过程:Redis 读取当前数据状态,生成一条条等价的 SET 命令写入新的 AOF 文件。

# 手动触发 AOF 重写
BGREWRITEAOF

重写过程同样通过子进程完成,利用 COW 机制,主进程几乎不受影响。重写期间的新写命令会同时写入旧 AOF 文件和一个重写缓冲区,子进程写完新文件后,主进程再把缓冲区里的增量命令追加到新文件末尾,最后用新文件替换旧文件。

自动触发的配置:

# 当 AOF 文件大小比上次重写后增长了 100% 时触发
auto-aof-rewrite-percentage 100

# AOF 文件最小达到 64MB 才考虑重写
auto-aof-rewrite-min-size 64mb

3.4 AOF 文件修复

# 检查 AOF 文件是否有损坏
redis-check-aof --fix appendonly.aof

# 查看 AOF 文件内容(可以看到具体的命令)
cat appendonly.aof

AOF 文件是文本格式(可以配置为混合格式),直接用 cat 就能看到里面的命令。排查问题时非常方便。

3.5 AOF 的优缺点

优点:

  • 数据安全性高。everysec 策略下最多丢 1 秒数据,always 下几乎不丢。

  • AOF 是文本文件(或混合文件),可读性强,便于排查问题。

  • 自动重写机制可以控制文件大小。

缺点:

  • 相同数据量下,AOF 文件通常比 RDB 大。

  • 恢复速度比 RDB 慢,因为要逐条重放命令(混合持久化改善了这一点)。

  • 频繁 fsync 会带来一定的性能开销。

4. 混合持久化(RDB-AOF Hybrid)

4.1 混合持久化解决什么问题

纯 AOF 的恢复速度慢,因为需要逐条执行命令。纯 RDB 的数据安全性差,因为两次快照之间有丢失窗口。

Redis 4.0 引入的混合持久化结合了两者的优点:

  • AOF 重写时,子进程把当前内存数据以 RDB 格式 写入 AOF 文件的开头。

  • 重写期间的增量命令继续以 AOF 格式 追加到文件后面。

这样,AOF 文件的结构变成了:

恢复时,Redis 先加载前面的 RDB 部分(速度快),再重放后面的 AOF 增量命令(数据新)。既保证了恢复速度,又保证了数据安全性。

4.2 开启混合持久化

# redis.conf(Redis 4.0+ 默认开启)
aof-use-rdb-preamble yes

设置为 yes 后,BGREWRITEAOF 生成的 AOF 文件就是混合格式。不需要额外操作,AOF 重写会自动按混合格式生成。

5. RDB 和 AOF 的选择与组合

5.1 生产环境的配置建议

根据不同的场景需求,常见的组合策略有以下几种:

追求性能,可以接受少量数据丢失:

# 只开 RDB
save 900 1
save 300 10
save 60 10000
# 关闭 AOF
appendonly no

适用于缓存、排行榜等非核心数据。Redis 挂了就挂了,从数据库重新加载就行。

追求数据安全,可接受小幅性能下降:

# 同时开 RDB 和 AOF
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes

适用于订单、支付等核心业务数据。绝大部分场景都推荐这套配置。

极致安全:

appendfsync always

每条写命令都刷盘,性能下降明显,一般只在金融、账务等对数据零容忍的场景使用。即便如此,也要先压测确认性能能否满足。

5.2 同时开启 RDB 和 AOF 时的恢复逻辑

Redis 重启时,如果同时存在 RDB 和 AOF 文件,优先使用 AOF 文件来恢复数据,因为 AOF 通常数据更完整。

如果只想要 RDB 的恢复速度但又需要 AOF 的数据安全,4.0 之后的混合持久化就是为此设计的。

5.3 数据恢复流程

# 1. 先把备份文件拷贝到 Redis 数据目录
cp dump.rdb /var/lib/redis/
cp appendonly.aof /var/lib/redis/

# 2. 检查文件完整性
redis-check-rdb dump.rdb
redis-check-aof --fix appendonly.aof

# 3. 启动 Redis
redis-server /etc/redis/redis.conf

启动后可以用 INFO Persistence 查看持久化状态:

redis-cli INFO Persistence

输出示例:

# Persistence
loading:0                        # 0 表示没有在加载数据
rdb_last_save_time:1680000000    # 上次 RDB 保存的时间戳
rdb_last_bgsave_status:ok        # 上次 BGSAVE 的状态
aof_enabled:1                    # AOF 是否开启
aof_last_write_status:ok         # 上次 AOF 写入的状态
aof_last_rewrite_time_sec:3      # 上次 AOF 重写耗时(秒)

6. 持久化相关的性能优化

6.1 fork 引起的阻塞

BGSAVE 和 BGREWRITEAOF 都需要 fork() 子进程。在内存大的实例上,fork 耗时可能达到秒级。

优化方向:

  • 控制单实例内存大小,建议不超过 16GB。超过的话考虑拆分或使用 Redis Cluster。

  • 避免在业务高峰期触发 BGSAVE 或重写。

  • 对 Linux 内核参数进行调优,关闭 THP(透明大页):

# 关闭透明大页,减少 fork 时的内存复制开销
echo never > /sys/kernel/mm/transparent_hugepage/enabled

6.2 AOF 刷盘策略的选择

always 策略下每次写都 fsync,性能影响巨大。大多数场景用 everysec 就够了。如果 Redis 部署在 SSD 上,fsync 的开销会更低,安全性也更有保障。

6.3 多核 CPU 的利用

持久化过程中,主进程只用一个 CPU 核心处理请求,子进程也只用另一个核心写文件。如果有 4 核 CPU,其实只用了 2 核。所以持久化不会明显拖慢 Redis,但也别指望它能充分利用多核。

7. 运维实践中的注意事项

7.1 定期备份 RDB 文件

即使开了 AOF,也建议保留 RDB 备份,因为 RDB 恢复快。常见做法是:

# crontab 定时任务:每天凌晨 3 点备份
0 3 * * * cp /var/lib/redis/dump.rdb /backup/redis/dump_$(date +\%Y\%m\%d).rdb

备份文件最好压缩后上传到对象存储或异地服务器,防止本机磁盘损坏。

7.2 AOF 文件大小监控

设置监控告警,当 AOF 文件超过阈值(比如 10GB)时及时处理。AOF 文件过大通常是重写没有正常触发或重写太慢导致的。

7.3 主从架构下的持久化

很多人在主库上关掉持久化,让从库来做。这种做法有一定风险:

  • 如果主从同时挂了(比如机房断电),数据全丢。

  • 从库做持久化时,主库的数据可能还没同步过来,存在不一致。

更稳妥的做法是:主库开 AOF(everysec),从库开 RDB(用于备份)。这样既保证了主库的数据安全,又有从库的冷备。

7.4 避免持久化引起的性能抖动

  • 设置 save 参数时,避免在短时间内触发太多次 BGSAVE。

  • 对于写密集场景,适当调高 auto-aof-rewrite-percentage,避免频繁重写。

  • 监控 info Persistence 中的 rdb_last_bgsave_time_sec(上次 BGSAVE 耗时)和 aof_last_rewrite_time_sec(上次重写耗时),如果耗时异常增长,说明内存数据量变大了,需要考虑拆分。

8. 总结

Redis 的持久化机制经历了三个阶段的演进:

  1. 纯 RDB 时代:简单,但丢数据多。

  2. RDB + AOF 并存:安全了,但恢复慢。

  3. 混合持久化(4.0+):兼顾恢复速度和数据安全,是目前的最佳实践。

我个人在实际项目中的经验是:大多数场景用 RDB(冷备)+ AOF(混合持久化,everysec)这套组合就足够了。数据安全性有保障,恢复速度也快,性能开销在可接受范围内。

如果是纯缓存场景,数据可以从数据库重新加载,关掉持久化也没问题。但如果是存储了计数器、分布式锁、排行榜等不可再生数据,持久化就是必须的,宁可牺牲一点性能也要保证数据不丢。

排查持久化问题的第一手工具,关键命令:

# 随时查看持久化状态
INFO Persistence

# 检查 AOF 文件健康度
redis-check-aof --fix appendonly.aof

最后,如有改进之处欢迎指正,觉得有帮助的话不妨点赞收藏支持一下,感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值