强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

09 - 持久化

持久化

Redis 是基于内存的数据库,如果进程退出或服务器宕机,内存中的数据会丢失。持久化机制确保数据能从磁盘恢复。

9.1 持久化概述

方式原理数据安全性恢复速度文件大小
RDB定时快照中(可能丢失最后一次快照后的数据)小(压缩)
AOF记录写命令高(最多丢失 1 秒数据)
混合持久化RDB + 增量 AOF

9.2 RDB 快照

工作原理

RDB 在指定时间间隔内将内存中的数据快照写入磁盘(dump.rdb 文件)。恢复时将 RDB 文件加载到内存。

内存数据 ──BGSAVE──→ fork 子进程 ──写入──→ dump.rdb
                    (不影响主进程)

dump.rdb ──加载──→ 恢复内存数据

触发方式

# 1. 配置自动触发
# redis.conf
save 3600 1        # 3600 秒内至少 1 次修改
save 300 100       # 300 秒内至少 100 次修改
save 60 10000      # 60 秒内至少 10000 次修改

# 2. 手动触发 - 同步保存(阻塞主线程,生产慎用!)
SAVE

# 3. 手动触发 - 后台异步保存(推荐)
BGSAVE
# Background saving started

# 4. 关闭服务器时自动保存
SHUTDOWN           # 自动触发 RDB 保存

# 5. 主从复制时,从节点首次同步触发

RDB 配置详解

# ---- 触发条件 ----
save 3600 1
save 300 100
save 60 10000

# 禁用 RDB(如果只用 AOF)
# save ""

# ---- 文件路径 ----
dbfilename dump.rdb
dir /var/lib/redis

# ---- 压缩 ----
rdbcompression yes           # LZF 压缩(推荐开启)
rdbchecksum yes              # CRC64 校验(推荐开启)

# ---- 错误处理 ----
stop-writes-on-bgsave-error yes   # RDB 保存失败时停止写入

# ---- 性能 ----
rdb-save-incremental-fsync yes    # 增量 fsync(减少写入峰值)

RDB 文件格式

┌──────────────────────────────────────────────┐
│              RDB 文件结构                     │
├──────────────────────────────────────────────┤
│ REDIS + 版本号 (5 字节 + 4 字节)              │
├──────────────────────────────────────────────┤
│ 辅助字段 (Redis 版本、创建时间、内存等)       │
├──────────────────────────────────────────────┤
│ 数据库 0                                      │
│   ├── SELECTDB + 数据库编号                   │
│   ├── RESIZEDB + 键值对数量 + 过期键数量      │
│   ├── 键值对数据(带过期时间则先写 EXPIRETIME │
│   └── ...                                     │
├──────────────────────────────────────────────┤
│ 数据库 1                                      │
│   └── ...                                     │
├──────────────────────────────────────────────┤
│ EOF 标记                                      │
├──────────────────────────────────────────────┤
│ CRC64 校验和                                  │
└──────────────────────────────────────────────┘

RDB 优缺点

优点缺点
文件紧凑,适合备份和灾难恢复可能丢失最后一次快照后的数据
恢复速度快(直接加载二进制)数据量大时 fork 子进程耗时
不影响主进程性能(BGSAVE)RDB 文件版本兼容性问题

9.3 AOF 日志

工作原理

AOF 将每一个写命令追加到日志文件末尾(appendonly.aof)。恢复时重放所有命令。

客户端写入 ──→ 追加到 AOF 缓冲区 ──fsync──→ appendonly.aof
                                    │
                              ┌─────┴─────┐
                              │           │
                         always       everysec
                       (每次写入)    (每秒,推荐)

AOF 同步策略

策略刷盘频率数据安全性能
always每次写命令最高(不丢数据)最差
everysec每秒一次高(最多丢 1 秒)好(推荐)
no由操作系统决定低(可能丢失大量数据)最好
# 查看当前 AOF 同步策略
redis-cli CONFIG GET appendfsync
# 1) "appendfsync"
# 2) "everysec"

# 运行时修改(不推荐频繁修改)
redis-cli CONFIG SET appendfsync everysec

AOF 配置详解

# ---- 开启 AOF ----
appendonly yes
appendfilename "appendonly.aof"

# ---- 同步策略 ----
appendfsync everysec

# ---- AOF 重写 ----
# 触发条件 1:AOF 文件比上次重写后增长了 100%
auto-aof-rewrite-percentage 100

# 触发条件 2:AOF 文件至少达到 64MB
auto-aof-rewrite-min-size 64mb

# 重写期间是否暂停 fsync(对数据安全有影响)
no-appendfsync-on-rewrite no

# ---- 文件格式 ----
# Redis 7.0+ 使用 Multi-Part AOF
aof-use-rdb-preamble yes     # 混合持久化(推荐开启)

AOF 重写机制

随着时间推移,AOF 文件会不断增长。AOF 重写会创建一个新的精简 AOF 文件:

原始 AOF 文件:
  SET key1 "a"
  SET key1 "b"      ← 覆盖前一条
  DEL key2
  SET key3 "c"

重写后 AOF 文件:
  SET key1 "b"      ← 只保留最新状态
  SET key3 "c"
# 手动触发 AOF 重写
BGREWRITEAOF
# Background append only file rewriting started

# 查看 AOF 文件信息
redis-cli INFO persistence | grep aof
# aof_enabled:1
# aof_rewrite_in_progress:0
# aof_rewrite_scheduled:0
# aof_last_rewrite_status:ok
# aof_current_size:1048576
# aof_base_size:524288

AOF 文件损坏修复

# AOF 文件损坏时尝试修复
redis-check-aof --fix appendonly.aof

# 验证修复后的文件
redis-check-aof appendonly.aof

AOF 优缺点

优点缺点
数据安全性高(最多丢 1 秒)文件比 RDB 大
可读性好(文本格式命令)恢复速度慢(重放命令)
支持增量写入AOF 重写期间占用额外内存

9.4 混合持久化(Redis 4.0+)

混合持久化结合了 RDB 的快速加载和 AOF 的增量记录:

AOF 重写后的文件:
┌─────────────────────────────────────┐
│  RDB 格式的数据快照                  │  ← 快速加载
│  (二进制,与 RDB 文件格式相同)       │
├─────────────────────────────────────┤
│  增量 AOF 命令                       │  ← 记录重写期间的新写入
│  (增量 SET key1 val1 ...)           │
└─────────────────────────────────────┘
# 开启混合持久化
redis-cli CONFIG SET aof-use-rdb-preamble yes

# 恢复时:先加载 RDB 部分(快),再重放 AOF 部分(少)

持久化方案对比

方案数据安全恢复速度文件大小推荐场景
纯 RDB数据允许少量丢失
纯 AOF对数据安全要求极高
RDB + AOF生产环境推荐
关闭持久化N/AN/A纯缓存场景

💡 技巧:生产环境推荐同时开启 RDB 和 AOF,AOF 保证数据安全,RDB 用于冷备和灾难恢复。

9.5 fork 性能优化

BGSAVE 和 BGREWRITEAOF 都会 fork 子进程,fork 操作可能阻塞主进程。

fork 耗时因素

因素影响
内存越大fork 越慢(需复制页表)
Linux 版本较新版本 fork 更快
虚拟化环境fork 可能比物理机慢
# 查看最近一次 fork 耗时
redis-cli INFO stats | grep latest_fork_usec
# latest_fork_usec:1500    ← 1.5 毫秒

# fork 耗时参考
# 1 GB 内存:  约 20-30ms
# 10 GB 内存: 约 200-300ms
# 25 GB 内存: 约 500ms+

优化建议

# 1. 控制 Redis 实例内存(建议单实例不超过 10-15 GB)
maxmemory 10gb

# 2. 避免在高峰期执行 BGSAVE
# 可以通过脚本控制触发时间

# 3. 使用 Linux 大页内存时注意
# 大页内存会导致 fork 时 COW(Copy-On-Write)复制更多数据
# 建议关闭大页内存
echo never > /sys/kernel/mm/transparent_hugepage/enabled

# 4. AOF 重写期间暂停 fsync(减少 I/O 压力)
no-appendfsync-on-rewrite yes   # 但有数据丢失风险

# 5. 控制 AOF 重写触发频率
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 256mb  # 增大最小触发大小

# 6. 增量 fsync(Redis 3.2+)
rdb-save-incremental-fsync yes
aof-rewrite-incremental-fsync yes

9.6 备份策略

自动备份脚本

#!/bin/bash
# redis_backup.sh - Redis 自动备份脚本

BACKUP_DIR="/backup/redis"
REDIS_CLI="redis-cli"
DATE=$(date +%Y%m%d_%H%M%S)
KEEP_DAYS=7

# 创建备份目录
mkdir -p ${BACKUP_DIR}

# 触发 RDB 快照
${REDIS_CLI} BGSAVE

# 等待 BGSAVE 完成
while [ "$(${REDIS_CLI} LASTSAVE)" == "$LAST_SAVE" ]; do
    sleep 1
done

# 复制 RDB 文件
cp /var/lib/redis/dump.rdb ${BACKUP_DIR}/dump_${DATE}.rdb

# 压缩
gzip ${BACKUP_DIR}/dump_${DATE}.rdb

# 删除过期备份
find ${BACKUP_DIR} -name "*.rdb.gz" -mtime +${KEEP_DAYS} -delete

echo "[$(date)] Backup completed: dump_${DATE}.rdb.gz"

定时任务

# crontab -e
# 每小时备份一次
0 * * * * /opt/scripts/redis_backup.sh >> /var/log/redis_backup.log 2>&1

📌 业务场景

场景一:电商缓存持久化

# 电商缓存场景,允许少量数据丢失
save 900 1
save 300 100
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
maxmemory 8gb

场景二:金融数据持久化

# 金融场景,数据零丢失
save 60 1000
appendonly yes
appendfsync always    # 每次写入都同步(性能较差,但最安全)
aof-use-rdb-preamble yes

场景三:纯缓存场景

# 纯缓存,不需要持久化
save ""
appendonly no
maxmemory 16gb
maxmemory-policy allkeys-lru

🔗 扩展阅读