Skip to content

这是我学习 Redis 持久化与内存淘汰时整理的笔记。入门用法见《Redis 快速入门》,分布式锁见《Redis 分布式锁详解》——本文专注数据怎么不丢、内存满了怎么处理两个生产必问点。

一、解决什么问题

Redis 是内存数据库——数据都在内存里,进程一重启,数据全没了。生产环境这是不可接受的(缓存能重建,但登录态、限流计数、分布式锁这种数据丢了会出事)。

所以 Redis 需要持久化:把内存数据落盘,重启后能恢复。两条路线:

方案思路一句话
RDB定时给内存数据拍快照存文件"备份整个数据库"
AOF每条写命令追加进日志文件"重放命令恢复"

二、RDB:快照持久化

原理

把当前内存里的所有数据,序列化写入 dump.rdb 文件。触发方式:

bash
SAVE                  # 阻塞式保存(主线程干活,生产别用)
BGSAVE                # 后台保存(fork 子进程写,不阻塞主线程)
# 配置自动触发(默认):
save 900 1            # 900 秒内 ≥1 次写 → 快照
save 300 10           # 300 秒内 ≥10 次写 → 快照
save 60 10000         # 60 秒内 ≥1 万次写 → 快照

关键机制:fork + Copy-On-Write(COW)——BGSAVE 时 fork 出子进程,父子共享内存页;父进程继续写时,被改的页才复制一份。所以子进程拿到的是 fork 时刻的"一致性快照",不阻塞主线程。

优缺点

  • ✅ 恢复快(直接加载 rdb 文件)、文件紧凑(二进制压缩)
  • 两次快照之间的数据会丢(默认 5 分钟粒度,极端丢 5 分钟)
  • ❌ fork 大实例时,COW 可能让内存短暂翻倍 + 卡顿

三、AOF:追加式命令日志

原理

每次写命令(SET/DEL/INCR...)追加appendonly.aof 文件末尾。恢复时逐条重放。三个刷盘策略(appendfsync):

策略行为丢数据性能
always每次写都 fsync不丢(最多丢一条)最慢(磁盘 IO 瓶颈)
everysec(默认)每秒 fsync 一次最多丢 1 秒折中,生产推荐
no交给操作系统刷丢最多最快

AOF 重写(rewrite):日志无限追加会越来越大,且有很多冗余命令(SET k 1SET k 2SET k 3 只留最后一条)。BGREWRITEAOF 会把内存当前状态压缩成最小命令集重写文件。

Redis 7 实测:AOF 现在是目录结构(multi-part AOF)——appendonlydir/ 下三个文件:*.base.rdb(RDB 格式基座)+ *.incr.aof(增量命令)+ manifest(清单)。这本身就是"混合持久化"的实现:重启先秒载 base.rdb,再重放 incr.aof 增量。

优缺点

  • ✅ 数据丢失少(everysec 最多 1 秒)
  • ❌ 文件比 RDB 大、恢复慢(要重放全部命令)

四、RDB vs AOF 对比 + 混合持久化

维度RDBAOF
数据安全丢两次快照间数据(分钟级)everysec 丢 ≤1 秒
恢复速度慢(重放)
文件大小大(可重写压缩)
主线程影响fork 时可能卡fsync 时机影响
适用数据可重建、能容忍分钟级丢失数据重要、要秒级恢复

Redis 持久化:RDB vs AOF 对比

生产实践(Redis 4.0+)appendonly yes 开启混合持久化——AOF 重写时头部用 RDB 格式(秒级加载),后面追加增量命令(少丢数据),兼顾两者。

五、过期删除:数据到期的两种清理方式

键设了 EXPIRE 60 到期后,Redis 怎么删?

策略机制问题
惰性删除访问 key 时才检查是否过期,过期则删过期 key 一直没人访问就占着内存
定期删除每秒抽样检查部分过期 key 删除抽样不保证全删

结论:两者配合——惰性删除兜底"访问时正确",定期删除兜底"没人访问的过期键也被清理"。这也是面试常问的"Redis 为什么用惰性+定期,不用定时器":定时器每个 key 一个 timer,大量 key 时 CPU 扛不住。

六、内存淘汰:内存满了怎么办

maxmemory 设上限(如 1GB)后,写入超限时触发淘汰策略(maxmemory-policy):

策略行为场景
noeviction(默认)不淘汰,写入报错严禁丢数据的场景
allkeys-lru所有 key 中淘汰最久未用缓存场景首选
volatile-lru只淘汰设了过期时间的 key 中 LRU有"永久 key"要保留时
allkeys-random / volatile-random随机淘汰淘汰无所谓
allkeys-lfu / volatile-lfu按访问频率淘汰(LFU)访问热度差异大的场景

注:Redis 的 LRU 是近似 LRU(抽样 N 个再比 LRU,不是全量精确),maxmemory-samples 控制抽样数(默认 5,调大更精确更耗 CPU)。

七、实跑验证(Docker Redis 实测)

bash
# 启动 Redis 容器(挂载数据目录便于看文件)
docker run -d --name redis-persist -p 16379:6379 \
  -v redis-data:/data redis:7-alpine

① RDB 触发与恢复

bash
redis-cli -p 16379 set user:1 BinMaker
redis-cli -p 16379 save          # 手动触发快照
docker exec redis-persist ls /data   # 看到 dump.rdb
docker restart redis-persist     # 重启
redis-cli -p 16379 get user:1    # BinMaker(数据恢复 ✅)

② AOF 文件内容(开启后):

bash
redis-cli -p 16379 config set appendonly yes
redis-cli -p 16379 set user:2 Alice
docker exec redis-persist cat /data/appendonly.aof | head   # 看到 *3\r\n$3\r\nset...

③ 过期删除行为

bash
redis-cli -p 16379 set session:1 token EX 5
redis-cli -p 16379 ttl session:1    # 5 秒后 → -2(已过期)
redis-cli -p 16379 get session:1    # nil(惰性删除触发 ✅)

④ 内存淘汰

bash
redis-cli -p 16379 config set maxmemory 10mb
redis-cli -p 16379 config set maxmemory-policy allkeys-lru
redis-cli -p 16379 info stats | grep evicted_keys   # 淘汰计数增长

小结

  • 持久化两兄弟:RDB 快照(恢复快、丢分钟级数据)、AOF 命令日志(秒级恢复、文件大)——生产用混合持久化
  • 过期清理:惰性删除(访问时)+ 定期删除(抽样)配合,不用定时器
  • 内存淘汰:8 种策略,缓存场景 allkeys-lru 首选;禁丢数据用 noeviction
  • 下一篇可以看《Redis 哨兵与集群》(高可用:主从复制、哨兵故障转移、集群分片)——单机持久化解决"重启不丢",集群解决"一台挂了怎么办"。

验证说明:本文全部用 Docker Redis 7 容器实跑验证——① RDB:SAVE 生成 dump.rdb、重启后 GET user:1 恢复 ✅;② AOF:appendonlydir/*.incr.aof 里能看到 RESP 格式的 SET user:2 Alice 命令 + base.rdb/incr.aof/manifest 三文件结构 ✅;③ 过期:TTL 返回 -2、GET 返回 nil(惰性删除)✅;④ 淘汰:maxmemory 10mb + allkeys-lruredis-benchmark 写入 64MB,evicted_keys: 478,淘汰后继续写入正常 ✅。