过期、RDB 与 AOF 持久化原理

→ 返回 Redis

Redis 的数据主要在内存中。过期机制决定“何时把无效 key 从内存移除”,RDB/AOF 决定“进程或机器重启后能恢复到什么程度”;二者都不能替代异机副本和备份。


过期 key 如何删除

EXPIRE key 3600
TTL key                         # -1 永不过期,-2 不存在
PEXPIRE key 1000
EXPIREAT key 1893456000

Redis 为带 TTL 的 key 维护额外过期字典,采用两种策略配合:

  • 惰性删除:访问 key 时检查时间,已过期就删除并按不存在处理。优点是不浪费 CPU 扫描未访问 key;缺点是冷 key 可能长期占内存。
  • 定期删除:周期任务随机抽样带 TTL 的 key,删除已过期项;若过期比例仍高,会继续一轮但限制时间,避免长时间阻塞主线程。

这不是为每个 key 创建一个定时器。定时器数量巨大时会带来明显调度和内存成本。

副本通常由主节点发送 DEL/等价传播来保持一致,而不是各自独立决定过期时刻;故障切换后,新主节点再负责主动过期。

maxmemory 淘汰不是过期删除

内存达到 maxmemory 后,Redis 根据淘汰策略为新写入腾空间;没有到期的 key 也可能被淘汰。

策略行为
noeviction不淘汰,可能增加内存的写命令报错
allkeys-lru / allkeys-lfu在全部 key 中按近似 LRU/LFU 淘汰
volatile-lru / volatile-lfu只在设置 TTL 的 key 中淘汰
volatile-ttl优先淘汰剩余 TTL 较短的 key
allkeys-random / volatile-random在对应候选集合中随机淘汰

LRU/LFU 通常是采样近似算法,不是维护一个包含所有 key 的精确全局链表。


RDB 快照原理

RDB 保存某一时刻的数据集快照,适合备份、全量复制和快速加载。

save 900 1
save 300 10
save 60 10000
主进程 fork
   ├─ 父进程:继续处理客户端写入
   └─ 子进程:遍历 fork 时视图 → 临时 RDB → 原子替换旧文件

fork 后父子进程通过操作系统的写时复制(COW)共享物理内存页。子进程看到的是 fork 时刻的一致视图;父进程修改某页时,操作系统才复制该页。

RDB 的成本

  • 两次快照之间宕机,期间的数据可能丢失;
  • 数据集大时,fork 复制页表本身也可能造成延迟尖峰;
  • 快照期间写入越多,COW 复制的内存页越多,峰值内存越高;
  • 子进程遍历内存并写盘会争用 CPU、内存带宽和磁盘 I/O。

BGSAVE 在后台子进程生成快照;SAVE 会阻塞主线程,生产环境通常不直接使用。


AOF 写入、刷盘与恢复

AOF 记录会改变数据集的命令,使用 RESP 形式保存;重启时顺序重放,重建内存状态。

写命令执行成功
    ▼
追加到 AOF 内存缓冲区 aof_buf
    ▼
事件循环在合适阶段调用 write 写入 OS page cache
    ▼
按 appendfsync 策略调用 fsync 落到持久介质

“写入文件”和“真正持久化到磁盘”是两个不同动作:write 通常只进入内核 page cache,fsync 才要求操作系统把数据刷到持久介质。

appendonly yes
appendfsync everysec
appendfsync行为典型取舍
always每批写命令都同步刷盘数据更安全,吞吐和尾延迟较差
everysec后台线程通常每秒刷盘常用;异常断电理论上可能丢约 1 秒
no交给操作系统决定刷盘吞吐高,故障时可能丢更多

若上一次后台 fsync 长时间未完成,主线程是否延迟新的 AOF 写入还受 no-appendfsync-on-rewrite 等配置和具体状态影响。磁盘延迟会直接反映为 Redis 尾延迟,应监控 INFO persistence 与系统磁盘指标。

AOF 为什么需要重写

不断追加会保留大量可被压缩的历史,例如同一 key 连续 SET 一万次,恢复只需要最终状态。BGREWRITEAOF 根据当前内存数据生成等价且更紧凑的新 base 文件,而不是逐行整理旧 AOF。

重写期间父进程继续接收写请求:

  • Redis 7.0+ 使用多部件 AOF:一个 base 文件、一个或多个增量 AOF 文件,由 manifest 描述有效文件集合;重写完成后原子切换 manifest,并清理旧文件。
  • Redis 7.0 之前通常是单 AOF 文件,重写期间需要额外记录增量,再与新文件衔接。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes

开启 aof-use-rdb-preamble 后,重写产生的 base 部分采用 RDB 格式,其后的增量仍为 AOF 命令格式。这就是常说的混合持久化:加载速度接近 RDB,同时保留 AOF 的较小数据丢失窗口。

启动恢复

  1. 同时启用 RDB 和 AOF 时,Redis 通常优先用 AOF 恢复,因为它一般包含更新的数据。
  2. Redis 7.0+ 根据 AOF manifest 依次加载 base 与增量文件。
  3. 尾部因异常宕机而不完整时,可按配置截断到最后一条完整命令;严重损坏应先备份,再使用检查修复工具。

RDB、AOF 与复制不要混淆

机制目标能否单独保证不丢数据
RDB时间点快照、快速恢复、备份不能,存在快照窗口
AOF更细粒度地记录写命令取决于刷盘策略,仍需备份
主从复制在线副本与高可用异步复制可能丢最后写入
备份应对误删、磁盘损坏、灾难恢复需异机保存并定期演练恢复

无持久化主节点搭配自动重启存在风险:空数据主节点重启后,可能把“空数据集”继续复制给从节点。重要数据应明确设计持久化、备份和故障恢复策略。


生产检查

INFO persistence
LASTSAVE
CONFIG GET appendonly
CONFIG GET appendfsync

重点关注:rdb_last_bgsave_status、rdb_last_cow_size、aof_last_bgrewrite_status、aof_rewrite_in_progress、AOF 当前大小与 base 大小。


相关