为什么需要持久化
Redis 是内存数据库,进程崩溃或服务器断电后,内存数据全部消失。持久化机制将内存数据写入磁盘,使 Redis 在重启后能恢复数据,扮演"不那么纯粹"的内存数据库角色。
RDB:快照持久化
RDB(Redis Database Backup)在指定时间点将内存中的全部数据以二进制格式快照到 .rdb 文件。类似数据库的全量备份。
RDB fork-copy-on-write 机制
Redis 主进程(继续处理命令)
↓ fork()
子进程(遍历内存,写入 .rdb)
共享父进程内存页(写时复制)
如果父进程修改某页内存:
父进程 ──复制该页──▶ 新内存页(父进程使用)
原内存页(子进程继续读)
结论:RDB 期间父进程可正常工作,但大量写操作会导致内存翻倍
RDB 触发方式
自动触发(save 配置)
# redis.conf
# 900秒内有1次写操作
save 900 1
# 300秒内有10次写操作
save 300 10
# 60秒内有10000次写操作
save 60 10000
# 关闭 RDB
save ""
手动触发
# BGSAVE:异步(推荐)
# fork 子进程后立即返回
BGSAVE
# SAVE:同步(阻塞,慎用)
# 会阻塞 Redis 直到完成
SAVE
# 查看最后一次 RDB 保存时间
LASTSAVE
RDB 配置项
# redis.conf 关键配置
dbfilename dump.rdb # RDB 文件名
dir /var/lib/redis # 存储目录
rdbcompression yes # 使用 LZF 压缩(节省磁盘,略增 CPU)
rdbchecksum yes # 文件末尾加 CRC64 校验和
stop-writes-on-bgsave-error yes # BGSAVE 失败时停止写操作(保护数据一致性)
AOF:追加写日志
AOF(Append Only File)将每条写命令以 RESP 格式追加到 .aof 文件末尾,类似 MySQL 的 binlog。Redis 重启时重放所有命令来恢复数据。
AOF 文件格式(RESP 协议)
*3 ← 3 个参数
$3 ← 第1个参数长度3字节
SET ← 命令
$4 ← 第2个参数长度4字节
name ← key
$5 ← 第3个参数长度5字节
Redis ← value
AOF 同步策略(fsync)
AOF 写入分两步:先写到操作系统 page cache,再由 fsync 刷入磁盘。同步策略决定数据安全性和性能的权衡:
| appendfsync 配置 | fsync 时机 | 数据安全 | 性能影响 |
|---|---|---|---|
always | 每条命令执行后立即同步 | 最高(几乎不丢数据) | 最大(每次写磁盘) |
everysec(推荐) | 每秒同步一次 | 高(最多丢1秒数据) | 中(异步后台) |
no | 由操作系统决定(通常30秒) | 低(可能丢失30秒) | 最小 |
AOF 重写:压缩日志文件
AOF 文件会持续增大(如对同一 key 做了 1000 次 SET,文件里有 1000 条记录,但只有最后一条有效)。AOF 重写将内存当前状态转换为最小命令集:
AOF 重写前后对比
重写前 AOF(冗余):
SET counter 1
SET counter 2
SET counter 3
... (1000次)
SET counter 1000
重写后 AOF(精简):
SET counter 1000 ← 一条命令表达最终状态
# redis.conf AOF 配置
appendonly yes # 开启 AOF
appendfilename "appendonly.aof"
appendfsync everysec # 推荐:每秒同步
no-appendfsync-on-rewrite no # 重写期间是否暂停同步
# AOF 自动重写触发条件
auto-aof-rewrite-percentage 100 # 文件比上次重写后增长100%时触发
auto-aof-rewrite-min-size 64mb # 最小64MB才触发重写
# 手动触发 AOF 重写
BGREWRITEAOF
混合持久化(推荐生产配置)
Redis 4.0 引入混合模式:AOF 重写时,文件头部写入 RDB 格式的全量快照,尾部追加增量 AOF 命令。兼顾了 RDB 的快速恢复和 AOF 的数据安全。
混合持久化文件结构
┌───────────────────────────────────────────────┐
│ appendonly.aof │
│ ┌──────────────────────────────────────────┐ │
│ │ RDB 格式数据(某时刻的完整快照) │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ AOF 格式增量命令(快照之后的写操作) │ │
│ └──────────────────────────────────────────┘ │
└───────────────────────────────────────────────┘
恢复时:先加载 RDB(快)→ 再重放增量 AOF(少)
# 开启混合持久化
aof-use-rdb-preamble yes # Redis 7.x 默认已开启
数据恢复流程
Redis 启动时的持久化文件加载顺序
Redis 启动
↓
AOF 开启?
├── YES ──▶ 加载 AOF 文件(包含 RDB+AOF 混合内容)
└── NO ──▶ 加载 RDB 文件(如果存在)
↓
加载完成,开始对外服务
注意:如果 AOF 和 RDB 都存在,优先使用 AOF(数据更新)
持久化性能影响分析
| 方案 | 写性能影响 | 恢复速度 | 数据安全 | 文件大小 |
|---|---|---|---|---|
| 不持久化 | 无影响 | N/A(重启丢数据) | 最低 | N/A |
| RDB only | 低(fork 瞬间暂停微秒~毫秒) | 最快 | 低(可能丢几分钟) | 最小(压缩二进制) |
| AOF everysec | 中(后台 fsync) | 慢(重放命令) | 高(最多丢1秒) | 大(文本格式) |
| AOF always | 高(每次写磁盘) | 慢 | 最高 | 大 |
| 混合模式 | 中 | 快 | 高 | 中 |
fork 导致主进程阻塞:BGSAVE 和 BGREWRITEAOF 在 fork 时会短暂阻塞主进程(Linux 需要复制页表)。内存越大阻塞越长——100GB 内存的 Redis 实例 fork 可能阻塞数秒!应定期监控 INFO persistence 中的 rdb_last_bgsave_time_sec,并使用内存大页(Transparent Huge Pages)前需评估其对 fork 的影响。
生产环境推荐配置
# /etc/redis/redis.conf 生产推荐
# 混合持久化
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# RDB(作为额外备份)
save 3600 1 # 1小时有1次写则保存
save 300 100 # 5分钟有100次写则保存
rdbcompression yes
rdbchecksum yes
# 数据目录(建议独立磁盘)
dir /data/redis
dbfilename dump.rdb
# 检查持久化状态
redis-cli INFO persistence | grep -E "rdb_|aof_"
# 关键指标说明:
# rdb_last_bgsave_status: ok ← 最后一次 BGSAVE 是否成功
# rdb_last_bgsave_time_sec: 2 ← 上次 BGSAVE 耗时(秒)
# aof_current_size: 52428800 ← AOF 当前大小(字节)
# aof_rewrite_in_progress: 0 ← 是否正在重写