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
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?或者两者都用?这得看你的业务容忍度。
我画了一张决策流程图,帮你快速定位:
这张图的核心逻辑是:先问你能不能丢数据,再问你的机器扛不扛得住。
我的实战建议:
- 风控系统、订单状态机:必须用AOF,甚至可以考虑always策略
- 用户会话、临时缓存:RDB就够了,丢了也不心疼
- 核心交易数据:RDB + AOF 双开,互相兜底
4.3 交易系统重启后的数据恢复方案
重启恢复,说白了就是Redis启动时怎么把磁盘上的数据重新加载到内存里。这里面的坑,比你想的要多。
4.3.1 恢复优先级
Redis启动时,会按以下顺序检查并加载数据:
- 检查是否存在AOF文件(appendonly.aof)
- 如果存在,加载AOF文件恢复数据
- 如果不存在,检查RDB文件(dump.rdb)
- 如果存在,加载RDB文件恢复数据
- 如果都不存在,启动一个空实例
注意:如果同时开启了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