Redis 从入门到精通:持久化RDB 与 AOF

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。

Redis 以极致的性能著称,核心原因之一就是所有数据都在内存中读写。但内存的特性是易失的------一旦断电或进程崩溃,所有数据瞬间消失。如果 Redis 只做缓存还好,数据丢了可以从数据库重新加载;可当它承载着分布式锁、计数器、消息队列等关键业务数据时,丢数据就是事故。

因此,Redis 提供了两种持久化机制,将内存数据保存到磁盘:RDB(快照) 和 AOF(追加日志) ,以及它们的结合体------混合持久化。本文带你彻底理解这三种方案的工作原理、配置方法、优缺点和实战策略,让你面对"会不会丢数据"这类问题时从容作答。

1. 为什么需要持久化?

先理清一个概念:持久化不是"备份",而是数据从内存到磁盘的同步过程。它的价值体现在:

  • 故障恢复:进程崩溃或服务器重启后,能恢复数据,减少损失。

  • 数据迁移:将 RDB/AOF 文件复制到另一台机器,快速恢复整个数据集。

  • 冷备归档:定期保存某一时刻的完整数据快照。

当然,持久化不是免费的------它消耗磁盘 I/O、CPU 和内存,需要在性能 和数据安全之间做权衡。理解每种方案的原理,才能做出正确选择。

2. RDB(Redis Database)------ 内存快照

2.1 什么是 RDB?

RDB 就是在某个时间点 ,把 Redis 中所有数据 生成一份压缩的二进制快照文件 (默认名为 dump.rdb),保存到磁盘。

可以把它理解为:给 Redis 内存拍了一张"照片",这张照片就是当时全部数据的完整拷贝。

2.2 RDB 的触发方式

① 手动触发

bash 复制代码
# 阻塞主进程,直到保存完成(生产环境禁用)
127.0.0.1:6379> SAVE
OK

# 后台异步保存(推荐)
127.0.0.1:6379> BGSAVE
Background saving started
  • SAVE:在主进程中执行,保存期间 Redis 不能处理任何命令。数据量大时会严重阻塞,绝对不要在生产环境使用。

  • BGSAVE:fork 一个子进程,由子进程负责写入 RDB 文件,主进程继续处理请求。这就是我们日常使用的命令。

② 自动触发(配置文件中设置)

打开 redis.conf,你会看到类似这样的配置:

bash 复制代码
# 格式:save <seconds> <changes>
# 含义:在 N 秒内,如果至少有 M 个键被修改,就触发一次 BGSAVE

save 900 1      # 900 秒(15分钟)内,至少 1 个键被修改
save 300 10     # 300 秒(5分钟)内,至少 10 个键被修改
save 60 10000   # 60 秒内,至少 10000 个键被修改

多条规则是或 关系,满足任意一条就触发。也可以清空 save 配置来禁用自动 RDB(但 BGSAVE 手动触发仍有效)。

③ 其他自动触发场景

  • 主从复制时,主节点自动执行 BGSAVE 生成 RDB 文件发给从节点。

  • 执行 SHUTDOWN 关闭 Redis 时,如果没有开启 AOF,会自动执行一次 SAVE。

  • 执行 FLUSHALL 后,如果配置了自动保存规则,会触发一次 RDB(生成空快照,非常危险)。

2.3 RDB 工作原理(BGSAVE 流程)

bash 复制代码
主进程                          子进程
   │                              │
   ├── fork() ──────────────────> │  (写时复制,共享内存页)
   │                              │
   ├── 继续处理客户端命令          ├── 遍历所有数据
   │                              ├── 写入临时 RDB 文件
   │                              ├── 完成后,原子重命名为 dump.rdb
   │                              └── 退出
   │                              │
   └── 子进程结束,主进程继续服务

关键点:fork() 使用了操作系统的**写时复制(Copy-On-Write)**机制。fork 出的子进程和父进程共享同一块物理内存,只有当父进程修改数据时,操作系统才会把对应的内存页复制一份。这样既保证了子进程能看到 fork 瞬间的完整数据,又不会过度占用内存。

⚠️ 如果 fork 后父进程写入量很大,会导致大量内存页被复制,内存占用可能短时间内翻倍。这也是为什么 Redis 需要预留一半内存的原因之一。

2.4 RDB 配置详解

bash 复制代码
# redis.conf

# RDB 文件名
dbfilename dump.rdb

# RDB 文件保存路径(需确保 Redis 有写权限)
dir /data/redis

# 保存规则(前面已介绍)
save 900 1
save 300 10
save 60 10000

# 写入错误时是否停止接受写入(建议 yes)
stop-writes-on-bgsave-error yes

# 是否压缩 RDB 文件(CPU 换磁盘空间)
rdbcompression yes

# 是否对 RDB 文件做完整性校验
rdbchecksum yes

Python 中查看持久化配置:

bash 复制代码
import redis

r = redis.Redis(decode_responses=True)

# 查看 RDB 相关配置
for key in ['dbfilename', 'dir', 'rdbcompression', 'rdbchecksum']:
    print(f'{key}: {r.config_get(key)[key]}')

# 手动触发 BGSAVE
result = r.bgsave()
print(f'BGSAVE 是否触发: {result}')

# 查看最近一次 BGSAVE 是否成功(返回 Unix 时间戳)
last_save = r.lastsave()
print(f'上次成功保存时间: {last_save}')

输出示例:

bash 复制代码
dbfilename: dump.rdb
dir: /data
rdbcompression: yes
rdbchecksum: yes
BGSAVE 是否触发: True
上次成功保存时间: 1718092800

2.5 RDB 的优缺点

✅ 优点:

  • 文件紧凑:单一压缩二进制文件,非常适合冷备和灾难恢复。

  • 恢复速度快:直接加载二进制数据到内存,比逐条回放 AOF 快得多。

  • 性能影响小 :BGSAVE 由子进程完成,主进程只负责 fork,不影响正常请求处理。

  • 适合主从同步:主从复制首次全量同步直接传 RDB 文件。

❌ 缺点:

  • 会丢数据:两次 RDB 之间的数据没来得及持久化,一旦宕机就丢失。

  • 大数据量时 fork 代价高:内存越大,fork 越慢(毫秒到秒级),可能阻塞主进程。

  • 写时复制导致内存压力:频繁写入时,内存占用可能暴涨。

3. AOF(Append Only File)------ 命令日志

3.1 什么是 AOF?

AOF 记录的是每一条修改数据的 Redis 命令 (写入、删除、修改),按时间顺序追加到日志文件中。重启时,Redis 通过逐条回放 AOF 中的命令来重建数据。

可以把它理解为:不是给数据拍照,而是记录下了"拍照后发生的每一条改动"。

3.2 AOF 的开启与基本配置

bash 复制代码
# redis.conf
appendonly yes                 # 开启 AOF
appendfilename "appendonly.aof" # AOF 文件名
dir /data/redis                # 存放目录(与 RDB 共用)

重启 Redis 后,用 redis-cli 观察:

bash 复制代码
127.0.0.1:6379> SET name "IT策士"
OK
127.0.0.1:6379> SET age 30
OK
127.0.0.1:6379> INCR counter
(integer) 1

查看 AOF 文件内容(通过 Docker 进入容器或直接在服务器上):

bash 复制代码
$ cat /data/appendonly.aof
*3
$3
SET
$4
name
$8
IT策士
*3
$3
SET
$3
age
$2
30
*2
$4
INCR
$7
counter

AOF 文件是 Redis 协议格式的纯文本,可读可解析 。如果误操作 FLUSHALL,还可以手动编辑 AOF 文件删除那条命令然后恢复数据(仅限紧急情况)。

3.3 AOF 写入策略(appendfsync)

Redis 提供三种写入磁盘的策略,由 appendfsync 配置:

bash 复制代码
# 每次写命令都同步到磁盘(最安全,但最慢)
appendfsync always

# 每秒同步一次(默认,性能与安全的最佳平衡)
appendfsync everysec

# 完全依赖操作系统缓冲区刷新(最快,但可能丢大量数据)
appendfsync no

为什么 everysec 是最佳平衡?

Redis 主线程负责将 AOF 写入内存缓冲区,然后由单独的 AOF 刷盘线程 每秒执行一次 fsync 系统调用,将缓冲区数据真正写入磁盘。主线程不参与实际的磁盘写入,所以对性能影响极小。1 秒的数据丢失窗口,对于绝大多数互联网场景是可接受的。

3.4 AOF 重写(Rewrite)------ 防止文件无限膨胀

AOF 会不断追加命令,文件大小必然持续增长。假设一个计数器 INCR 了 100 次,AOF 里会有 100 条 INCR 命令,而实际上恢复数据只需要最后的值。

AOF 重写 就是 Redis 自己创建一个新的 AOF 文件,只包含重建当前数据集所需的最少命令。

bash 复制代码
# 手动触发重写
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

自动重写配置:

bash 复制代码
# 当 AOF 文件体积比上次重写后增长了 100%,且超过 64MB 时,自动触发重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

重写流程:

bash 复制代码
主进程                             子进程
  │                                  │
  ├── fork() ──────────────────────> │
  │                                  ├── 读取数据库数据
  │                                  ├── 生成新 AOF 文件(最小命令集)
  │                                  └── 退出
  ├── 期间的新命令同时写入:
  │   ├── 旧 AOF 缓冲区(正常 AOF)
  │   └── AOF 重写缓冲区(记录增量)
  │
  └── 子进程完成后,将重写缓冲区的增量写入新 AOF,然后原子替换旧 AOF

这个过程与 RDB 的 BGSAVE 非常类似,利用子进程和写时复制,主进程几乎不受影响。

3.5 AOF 相关配置总览

bash 复制代码
# 开启 AOF
appendonly yes

# 文件路径
appendfilename "appendonly.aof"

# 写入策略
appendfsync everysec

# 重写期间是否继续同步旧 AOF(yes 保证安全但可能阻塞)
no-appendfsync-on-rewrite no

# 自动重写触发条件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# AOF 文件尾部损坏时,是否允许启动(yes 会忽略尾部错误,尝试恢复)
aof-load-truncated yes

3.6 AOF 的优缺点

✅ 优点:

  • 数据更安全 :everysec 最多丢 1 秒数据,always 完全不丢。

  • 可读性好:AOF 文件是 Redis 协议文本,可直接查看和编辑。

  • 自动重写:防止文件无限增长,保持文件体积可控。

❌ 缺点:

  • 恢复速度慢:重新回放所有命令,大数据量时远比 RDB 慢。

  • 文件体积大:相同数据集,AOF 文件通常比 RDB 大。

  • 写入性能有损耗 :即使 everysec,每秒刷盘也会消耗 I/O。

4. 混合持久化 ------ Redis 4.0 的最佳方案

既然 RDB 恢复快但可能丢数据,AOF 数据安全但恢复慢,能否鱼与熊掌兼得?Redis 4.0 引入了混合持久化,完美融合了二者的优点。

4.1 混合持久化原理

混合持久化在 AOF 重写时生效。重写出的新 AOF 文件不是纯命令,而是两部分组成:

bash 复制代码
┌─────────────────────────────────────┐
│          RDB 格式的二进制数据          │  ← 重写瞬间的内存快照
│  (占文件前半部分)                    │
├─────────────────────────────────────┤
│          AOF 格式的增量命令           │  ← 重写过程中新产生的命令
│  (占文件后半部分)                    │
└─────────────────────────────────────┘
  • 前半部分是 RDB 格式,包含了重写时刻的全部数据,体积小,加载快。

  • 后半部分是 AOF 命令,记录了重写过程中新增的数据修改。

重启加载时,Redis 先读 RDB 部分快速恢复大部分数据,再回放少量 AOF 增量命令,既快又完整。

4.2 开启混合持久化

bash 复制代码
# redis.conf(Redis 4.0+ 支持)
aof-use-rdb-preamble yes

查看并设置:

bash 复制代码
127.0.0.1:6379> CONFIG GET aof-use-rdb-preamble
1) "aof-use-rdb-preamble"
2) "yes"
127.0.0.1:6379> CONFIG SET aof-use-rdb-preamble yes
OK

Python 中检查和触发 AOF 重写:

bash 复制代码
import redis

r = redis.Redis(decode_responses=True)

# 查看混合持久化是否开启
preamble = r.config_get('aof-use-rdb-preamble')['aof-use-rdb-preamble']
print(f'混合持久化: {"开启" if preamble == "yes" else "关闭"}')

# 查看 AOF 信息
info = r.info('persistence')
print(f"AOF 开启: {info['aof_enabled']}")
print(f"AOF 当前大小: {info['aof_current_size']} bytes")
print(f"AOF 基础大小: {info['aof_base_size']} bytes")

# 手动触发 AOF 重写
r.bgrewriteaof()
print("已触发 BGREWRITEAOF")

4.3 混合持久化的优缺点

✅ 优点:

  • 恢复速度快:RDB 部分加载快,附加少量 AOF 回放。

  • 数据完整:AOF 增量保证了重写期间的数据不丢失。

  • 文件体积可控:每次重写生成新文件,比纯 AOF 更小。

❌ 缺点:

  • 可读性降低 :文件前部分是二进制,不能直接 cat 查看。

  • 兼容性:仅 Redis 4.0+ 支持,老版本无法读取混合格式。

💡 生产推荐 :同时开启 RDB 和 AOF,开启混合持久化。这是目前最广泛使用也是最稳妥的方案。

5. 备份恢复策略

5.1 数据备份

无论 RDB 还是 AOF,都应该定期将持久化文件备份到其他存储介质(云存储、NAS、异地机器)。

bash 复制代码
# 备份 RDB 文件
cp /data/redis/dump.rdb /backup/redis/dump_$(date +%Y%m%d_%H%M).rdb

# 备份 AOF 文件
cp /data/redis/appendonly.aof /backup/redis/aof_$(date +%Y%m%d_%H%M).aof

Python 自动化备份脚本(配合 crontab 定时执行):

bash 复制代码
import redis
import shutil
import os
from datetime import datetime

r = redis.Redis(decode_responses=True)

# 1. 触发 BGSAVE,确保 RDB 是最新的
r.bgsave()

# 2. 获取 RDB 文件路径
dir_path = r.config_get('dir')['dir']
rdb_file = r.config_get('dbfilename')['dbfilename']
rdb_path = os.path.join(dir_path, rdb_file)

# 3. 备份到指定目录(加上时间戳)
backup_dir = '/backup/redis'
os.makedirs(backup_dir, exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_path = os.path.join(backup_dir, f'dump_{timestamp}.rdb')
shutil.copy2(rdb_path, backup_path)

print(f'备份完成: {backup_path}')
print(f'文件大小: {os.path.getsize(backup_path)} bytes')

5.2 数据恢复

恢复流程:

  1. 停止 Redis。

  2. 将备份的持久化文件复制到 Redis 数据目录。

  3. 启动 Redis,它会自动加载持久化文件。

bash 复制代码
# 1. 停止 Redis
redis-cli shutdown
# 或 docker stop redis-lab

# 2. 复制备份文件
cp /backup/redis/dump_20260101_0300.rdb /data/redis/dump.rdb

# 3. 重启 Redis
redis-server /etc/redis/redis.conf
# 或 docker start redis-lab

⚠️ 如果同时存在 dump.rdb 和 appendonly.aof,Redis 优先加载 AOF 文件(因为它通常数据更完整)。

5.3 AOF 文件修复

如果 AOF 文件损坏导致 Redis 无法启动:

bash 复制代码
# Redis 自带修复工具
redis-check-aof --fix appendonly.aof

它会截断 AOF 文件到最后一个有效命令处,舍弃尾部损坏部分。

6. 实战:Docker 环境配置持久化

用 Docker 启动一个开启了 RDB + AOF + 混合持久化的 Redis:

bash 复制代码
# 创建本地目录用于挂载
mkdir -p ~/redis-data

# 启动容器
docker run -d \
  --name redis-persist \
  -p 6379:6379 \
  -v ~/redis-data:/data \
  redis:7.2 redis-server \
  --appendonly yes \
  --appendfsync everysec \
  --aof-use-rdb-preamble yes \
  --save 900 1 \
  --save 300 10 \
  --save 60 10000

验证:

bash 复制代码
# 进入容器
docker exec -it redis-persist redis-cli

127.0.0.1:6379> CONFIG GET appendonly
1) "appendonly"
2) "yes"
127.0.0.1:6379> CONFIG GET aof-use-rdb-preamble
1) "aof-use-rdb-preamble"
2) "yes"

# 写一些数据
127.0.0.1:6379> SET test "persistence"
OK

# 查看持久化文件
# 在宿主机:ls -lh ~/redis-data/

7. 选型决策树

bash 复制代码
你的 Redis 用途是什么?
│
├── 纯缓存(数据可重建)
│   └── 关掉所有持久化,性能极致
│
├── 一般业务(允许丢 1 分钟数据)
│   └── 只开 RDB,配置 save 规则
│
├── 重要业务(最多丢 1 秒)
│   └── 开 AOF everysec,定期 BGREWRITEAOF
│
└── 核心业务(几乎不能丢数据)
    ├── RDB + AOF everysec
    ├── 开启混合持久化
    └── 配合主从 + 定期异地备份

8. 动手试试

  1. 体验 RDB :开启 Redis,设置 save 60 1,写入若干键,等待 60 秒观察 dump.rdb 的生成时间和大小。模拟宕机(docker restart),检查数据是否恢复。

  2. 体验 AOF 重写 :循环写入 10 万条 SET,查看 appendonly.aof 文件大小。手动执行 BGREWRITEAOF,对比重写前后的文件大小。

  3. 混合持久化对比 :分别用纯 AOF 和混合持久化方式写入同样的数据,重写后对比文件大小和 redis-benchmark 恢复速度。

  4. 模拟恢复:删除 Redis 容器并重新创建,挂载之前的持久化文件,验证数据是否完整恢复。

预期效果:RDB 快照恢复后丢失快照后写入的数据;AOF 恢复完整但慢;混合持久化恢复快且数据完整。

9. 总结

本文我们深入了 Redis 持久化三大方案:

核心要点:

  • RDB 是"拍照",AOF 是"录像",混合是"先拍照再录像"。

  • everysec 是 AOF 写入策略的甜点。

  • Redis 4.0+ 一律开启混合持久化。

  • 持久化文件要异地备份,并定期演练恢复。

持久化是 Redis 数据安全的基石。掌握了它,你就懂得了如何在性能和安全之间游刃有余地取舍。下一章,我们将进入 Redis 高可用架构的第一站------主从复制,看如何通过多副本提高数据安全和读吞吐量。

想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !

相关推荐
这个DBA有点耶15 分钟前
从INDEX到JOIN_ORDER:MySQL 8.0 Hint语法体系与五类实战场景
数据库·mysql·架构
数字新视界20 分钟前
机房动环监控助力智能管理
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
梅菲塔亚24 分钟前
博客_Redis入门到实战
数据库·redis·缓存
abcyuu28 分钟前
用友 U8 Cloud 生产制造模块深度解析:从 BOM 建立到成本核算的技术实现
前端·数据库·制造
夜雪一千30 分钟前
MySQL 的ID用什么数据类型更好?主键ID选型实战
数据库·mysql
蓝胖的四次元口袋36 分钟前
Redis 知识梳理(3)
数据库·redis·缓存
一铭111991 小时前
海豹办公 1.9.15 跨端办公软件实践 文档兼容 Access 数据库与移动 WebView 排错
android·数据库·electron·开源软件·access
Lynne3091 小时前
TSN 在变电站自动化通信网络升级中的应用价值与技术挑战
服务器·网络·数据库
弈栈录1 小时前
用户、会话与消息表应该如何设计
数据库·后端
内存漫游1 小时前
Checkpoint 与 Crash Recovery:数据库恢复机制入门
数据库