4、Redis持久化策略:RDB与AOF的配置选择,以及交易系统重启后的数据恢复方案

说到Redis持久化,很多刚接触交易系统的朋友会觉得——Redis不就是个缓存吗?挂了重启不就完了?

嗯,这话在一般场景下没毛病。但在交易系统里,Redis里存的往往是订单状态、风控指标、用户持仓快照。一旦丢了,轻则数据对不上,重则直接造成资金损失。

我经历过一次线上事故,Redis意外宕机,RDB快照还是6小时前的。重启后风控计数器全部归零,导致短时间内放过了大量本该拦截的订单。那叫一个酸爽。

所以今天咱们好好聊聊RDB和AOF,以及交易系统重启后怎么把数据安全地恢复回来。

4.1 RDB与AOF:两种持久化的底层逻辑

Redis提供了两种持久化方式,说白了就是两种「存盘」策略。我习惯把它们理解成:

  • RDB(快照):定期给内存数据拍一张照片,存到磁盘上
  • AOF(追加文件):把每一条写命令都记下来,像日志一样

你想想看,这两种方式本质上就是「空间换时间」和「时间换空间」的经典博弈。

4.1.1 RDB的工作原理

RDB通过fork子进程,把当前内存中的数据全量写入一个临时文件,写完后替换旧的dump.rdb文件。这个过程是异步的,不会阻塞主线程处理请求。

我在项目中遇到过一个问题:交易高峰期,Redis内存占用达到8GB,RDB触发时fork子进程导致瞬间内存翻倍,直接触发了OOM Killer。后来怎么解决的?后面会讲。

RDB的配置很简单,在redis.conf里:

# 900秒内至少有1个key变化,触发快照
save 900 1
# 300秒内至少有10个key变化,触发快照
save 300 10
# 60秒内至少有10000个key变化,触发快照
save 60 10000

# 快照压缩,默认开启
rdbcompression yes

# 快照文件名
dbfilename dump.rdb
注意:save配置是「或」的关系,满足任意一条就会触发。交易系统里如果写入量很大,建议把60秒那条调高,避免频繁fork。

4.1.2 AOF的工作原理

AOF记录的是写命令本身。每次写操作完成后,Redis把命令追加到aof_buf缓冲区,然后根据配置的策略刷到磁盘。

AOF有三种刷盘策略:

策略 说明 安全性 性能
appendfsync always 每次写操作都刷盘 最高,最多丢一条命令 最慢,TPS下降明显
appendfsync everysec 每秒刷一次盘 中等,最多丢1秒数据 较好,推荐交易系统使用
appendfsync no 由操作系统决定何时刷盘 最低,可能丢大量数据 最快,但别用

我个人建议交易系统用everysec。always太慢,no太危险。everysec在性能和安全性之间取得了不错的平衡。

4.2 交易系统场景下的配置选择

选RDB还是AOF?或者两者都用?这得看你的业务容忍度。

我画了一张决策流程图,帮你快速定位:

交易系统Redis持久化策略决策流程 开始选择持久化策略 能否接受丢数据? 使用AOF 使用RDB 内存 > 4GB? 写入量 > 1万/s? RDB + 从库持久化 纯RDB即可 TPS > 5000? AOF everysec AOF always

这张图的核心逻辑是:先问你能不能丢数据,再问你的机器扛不扛得住

我的实战建议:

  • 风控系统、订单状态机:必须用AOF,甚至可以考虑always策略
  • 用户会话、临时缓存:RDB就够了,丢了也不心疼
  • 核心交易数据:RDB + AOF 双开,互相兜底

4.3 交易系统重启后的数据恢复方案

重启恢复,说白了就是Redis启动时怎么把磁盘上的数据重新加载到内存里。这里面的坑,比你想的要多。

4.3.1 恢复优先级

Redis启动时,会按以下顺序检查并加载数据:

  1. 检查是否存在AOF文件(appendonly.aof)
  2. 如果存在,加载AOF文件恢复数据
  3. 如果不存在,检查RDB文件(dump.rdb)
  4. 如果存在,加载RDB文件恢复数据
  5. 如果都不存在,启动一个空实例

注意:如果同时开启了RDB和AOF,Redis优先使用AOF恢复。因为AOF的数据更完整。

4.3.2 交易系统的恢复策略

我经历过一次惨痛的教训:交易系统凌晨重启,AOF文件有20GB,加载花了40分钟。这40分钟里,所有依赖Redis的服务全部不可用。

后来我设计了一套「分级恢复」方案:

恢复级别 适用场景 恢复时间 数据完整性
快速恢复 非核心缓存、临时数据 < 1分钟 可能丢失部分数据
标准恢复 一般业务数据 1-5分钟 丢失1秒内数据
完整恢复 核心交易数据、风控状态 5-30分钟 不丢失任何数据

具体怎么做?我一般这样配置:

# 核心交易实例:RDB + AOF 双开
save 60 1000
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 非核心缓存实例:仅RDB
save 300 100
appendonly no

小技巧:交易系统重启前,先手动执行一次BGSAVE生成最新RDB。这样即使AOF加载失败,也能用RDB兜底。我习惯在重启脚本里加上:

redis-cli BGSAVE
# 等待BGSAVE完成
while [ "$(redis-cli lastsave)" -lt "$(date +%s -d '1 minute ago')" ]; do
  sleep 1
done

4.3.3 AOF文件损坏怎么办?

我曾经遇到过机房断电,AOF文件写了一半就停了。重启时Redis直接报错,拒绝启动。

别慌,Redis提供了修复工具:

# 修复AOF文件
redis-check-aof --fix appendonly.aof

# 修复RDB文件
redis-check-rdb dump.rdb

修复原理很简单:把不完整的命令删掉,保留完整的数据。修复后可能会丢失最后几条命令,但总比整个实例起不来强。

重要提醒:修复前一定要备份原文件!我见过有人直接在原文件上修复,结果修坏了,连备份都没有。正确的做法是:
cp appendonly.aof appendonly.aof.bak
redis-check-aof --fix appendonly.aof

4.4 交易系统的持久化最佳实践

说了这么多,最后总结几条我踩过坑之后沉淀下来的经验:

  • 核心数据必须双开:RDB做全量备份,AOF做增量保护。别嫌麻烦,出一次事你就知道值了
  • 控制AOF文件大小:开启auto-aof-rewrite,定期重写压缩。我一般设置到64MB就开始重写
  • RDB不要设太频繁:交易高峰期fork子进程会消耗内存,建议把save 60 10000改成save 120 10000
  • 定期演练恢复流程:每季度至少做一次恢复演练,确保备份文件可用。我见过备份文件损坏半年没人发现的
  • 监控持久化状态:用info persistence命令查看last_save_time、aof_current_size等指标,接入告警

持久化这件事,平时看着不起眼,出事的时候就是救命稻草。别等到数据丢了才想起来配置,那时候就晚了。


公众号:蓝海资料掘金营,微信deep3321