两种机制的底层差异
RDB 是**时间点快照**:把某一时刻整个数据集压缩成一个二进制文件,写到 `dump.rdb`。它的优点是紧凑、恢复快(加载一个文件即可),缺点是两次快照之间的所有写入都没有记录,丢失窗口等于快照间隔。
AOF 是**操作日志**:把每一条写命令按 Redis 协议格式追加到 `appendonly.aof` 文件尾部,恢复时重放整个文件。它的优点是丢失窗口小到「最多最后一次未刷盘的写入」,缺点是文件会不断膨胀,需要重写(`BGREWRITEAOF`)来压缩。
Redis 7 引入了 **multi-part AOF**:把 AOF 拆成一个基础文件(base file,通常由 RDB 格式的快照充当)加若干增量文件( incr files)。重写不再需要「先写临时文件再原子改名」的复杂流程,重写期间的新增量单独成文件,恢复时先加载 base 再依次重放 incr。这让 AOF 的重写成本与恢复时间都大幅下降。
实践中最常被低估的一点:**RDB 快照期间的写入不会丢**。BGSAVE 触发时会先记录当前的数据字典版本号,快照期间的新写入先进入复制缓冲区,快照完成后再决定是否需要额外保存。因此 BGSAVE 的数据一致性是有保证的,「做快照时写入会丢」是个常见误解。
# 状态查看
INFO persistence
# rdb_changes_since_last_save : 上次快照后的写入次数(越大丢失风险越高)
# rdb_last_bgsave_status : ok / err
# aof_rewrite_in_progress : 是否正在重写
# aof_last_bgrewrite_status : ok / err
CONFIG GET appendonly
CONFIG GET appendfsync
CONFIG GET dir
CONFIG GET dbfilenameappendfsync 三档的取舍
`always`:**每条写入都 fsync 到磁盘后才回复客户端**。丢失窗口接近零(最多丢最后一条未确认的写入,且操作系统层面的页缓存丢失仍在理论上存在),但吞吐会被磁盘 IOPS 限制,通常只有几千到一万次写/秒。适合订单、账务等不能丢钱的场景。
`everysec`:**每秒 fsync 一次**。这是官方推荐的默认平衡点:最坏情况下丢失最近一秒的写入,吞吐通常能到数万次/秒。绝大多数业务选它都不亏。注意 Redis 7+ 在 `everysec` 下对写入做了优化,主线程不再直接阻塞在 fsync 上。
`no`:**交给操作系统决定**,通常每 30 秒由内核写一次,也可能更久甚至在断电时全部丢失。吞吐最高,但你的持久化承诺实际上不存在。只在明确知道 Redis 仅作缓存、且有其他数据源可重建时才用。
选择建议:先问自己「Redis 挂了,从它恢复的数据能不能重建?」能重建就关掉持久化或用 no(纯缓存);不能重建就用 everysec;如果重建不了且丢失一秒都不可接受(比如作为唯一的消息队列或锁服务),才上 always。通常从 everysec 起步,看到实际 fsync 耗时再决定是否收紧。
# 纯缓存(可重建)
appendonly no
# save 置空以关闭 RDB 快照
# 通用推荐
appendonly yes
appendfsync everysec
# 强一致要求
appendonly yes
appendfsync always主从切换与数据完整性
Redis 复制默认是**异步**的。这意味着主节点可能已经回复客户端「写入成功」,但这次写入还没同步到从节点,主节点就宕机了——切换到从节点后这笔数据就丢了。这个窗口的大小取决于网络延迟和从节点的 `repl_ack` 频率。
在 `min-replicas-to-write` 与 `min-replicas-max-lag` 这两个参数的配合下,可以把异步复制的风险显式化:设置 `min-replicas-to-write=1` 与 `min-replicas-max-lag=2` 后,如果从节点少于 1 个或延迟超过 2 秒,主节点会**拒绝写入**。这是把「可能丢数据」换成「可能不可用」的显式决策。
另一个数据完整性要点是**过期键在主从间不一致**。Redis 7 起 `REPLICAOF` 使用复制流传播过期时间,但删除仍需从节点自行判断;网络抖动期间主从的过期状态可能短暂不一致。关键业务不应把「键过期」当作唯一的一致性保障。
如果你的场景真的要求同步复制,可以用 `WAIT` 命令:写入后调用 `WAIT 1 1000` 等待至少 1 个从节点确认、超时 1 秒。这是 Redis 提供的事务外一致性确认机制,用它可以在保持异步复制高性能的同时,对关键写入做强一致确认。
REPLICAOF NO ONE
# 查看复制状态
INFO replication
# master_repl_offset / slave0:offset=<n>,lag=<n seconds>
SET balance:1001 9900
WAIT 1 1000 # 等待 1 个从节点确认,最多等 1000ms
# 拒绝写入模式
min-replicas-to-write 1
min-replicas-max-lag 2配置模板与验证方法
推荐的通用起点是:AOF 开启、`appendfsync everysec`、`auto-aof-rewrite-percentage 100`、`auto-aof-rewrite-min-size 64mb`。后两个参数保证 AOF 文件增长到超过 64MB 且相比重写后翻倍时自动触发重写,不需要人工干预。
验证持久化是否真的生效,比看配置文件更可靠。最直接的方法是:写入一个键,杀掉 Redis 进程,重启后检查键是否存在。生产上可以用 `DEBUG RELOAD`(会阻塞,不建议)或在测试环境用 `SHUTDOWN NOSAVE` 与 `SHUTDOWN SAVE` 对比效果。
监控上要盯两个指标:`rdb_changes_since_last_save` 持续增长说明快照间隔太长或一直没成功;`aof_rewrite_in_progress` 长时间为 1 说明重写卡住了。此外 `INFO persistence` 里的 `aof_last_write_status: err` 是必须配告警的硬指标。
最后提醒一个迁移陷阱:从 Redis 6 升级到 7 时,AOF 格式发生变化(multi-part AOF),旧版本的 `appendonly.aof` 是单个文件。升级前先确认当前 Redis 版本,并在升级后检查 AOF 是否成功加载——若加载失败,Redis 会以空数据集启动,那是最糟糕的静默数据丢失。
# 推荐的通用配置
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 验证
redis-cli INFO persistence
redis-cli CONFIG GET appendonly
redis-cli LASTSAVE