Skip to content

Redis 基于RDB的恢复

RDB恢复原理

1. RDB文件结构

  • RDB文件组成

    • 魔数(Magic Number):标识文件类型
    • Redis版本号:记录生成RDB文件的Redis版本
    • 数据库数量:包含的数据库个数
    • 数据库内容:键值对数据,包括过期时间、数据类型、数据值
    • 校验和:用于验证文件完整性
  • RDB文件特点

    • 二进制格式,占用空间小
    • 恢复速度快于AOF
    • 不适合实时恢复,适合全量备份恢复
    • 支持压缩,可配置压缩级别

2. RDB恢复过程

┌─────────────────────────────────────────────────────────┐
│                                                       │
│  1. 启动Redis服务器                                   │
│  │                                                   │
│  └─► 2. 检测RDB文件是否存在                          │
│      │                                               │
│      ├─► 是 ──► 3. 验证RDB文件完整性                  │
│      │           │                                   │
│      │           ├─► 完整 ──► 4. 加载RDB文件到内存    │
│      │           │           │                       │
│      │           │           └─► 5. 恢复完成,对外服务 │
│      │           │                                   │
│      │           └─► 不完整 ──► 6. 记录错误日志        │
│      │                                   │           │
│      │                                   └─► 7. 启动失败│
│      │                                               │
│      └─► 否 ──► 8. 直接启动,创建空数据库             │
│                                                       │
└─────────────────────────────────────────────────────────┘
  • 恢复流程说明
    1. Redis服务器启动时,会检查配置文件中指定的RDB文件路径
    2. 如果RDB文件存在,Redis会尝试加载RDB文件
    3. 加载前会验证RDB文件的完整性(使用校验和)
    4. 加载过程中,Redis会阻塞对外服务,直到加载完成
    5. 加载完成后,Redis开始对外提供服务
    6. 如果RDB文件损坏,Redis会记录错误并启动失败

恢复前准备

1. RDB文件准备

  • 检查RDB文件

    bash
    # 查看RDB文件信息
    ls -la /var/lib/redis/dump.rdb
    
    # 检查RDB文件大小
    du -h /var/lib/redis/dump.rdb
    
    # 检查RDB文件创建时间
    stat /var/lib/redis/dump.rdb
  • 验证RDB文件完整性

    bash
    # 使用redis-check-rdb工具验证
    redis-check-rdb /var/lib/redis/dump.rdb
    
    # 示例输出(完整文件):
    # [offset 0] Checking RDB file /var/lib/redis/dump.rdb
    # [offset 26] AUX FIELD redis-ver = '7.0.0'
    # [offset 40] AUX FIELD redis-bits = '64'
    # [offset 52] AUX FIELD ctime = '1630000000'
    # [offset 67] AUX FIELD used-mem = '1000000'
    # [offset 83] Selecting DB ID 0
    # [offset 150] Checksum OK
    # [offset 150] 
    # 
    # Redis version found in RDB: 7.0.0
    # RDB version: 9
    # Number of DBs found: 1
    # DB 0: 1000 keys (0 volatile)
    # 
    # All information is good, RDB can be loaded by Redis

2. 环境准备

  • 停止当前Redis服务

    bash
    systemctl stop redis
    # 或
    redis-cli shutdown
  • 备份当前数据(可选):

    bash
    # 备份当前RDB文件
    mkdir -p /backup/redis/$(date +%Y%m%d)
    cp /var/lib/redis/dump.rdb /backup/redis/$(date +%Y%m%d)/dump.rdb.$(date +%H%M%S)
    
    # 如果启用了AOF,也备份AOF文件
    if [ -f /var/lib/redis/appendonly.aof ]; then
      cp /var/lib/redis/appendonly.aof /backup/redis/$(date +%Y%m%d)/appendonly.aof.$(date +%H%M%S)
    fi
  • 准备恢复目录

    bash
    # 确保Redis数据目录存在
    mkdir -p /var/lib/redis
    
    # 设置正确的权限
    chown -R redis:redis /var/lib/redis
    chmod -R 755 /var/lib/redis

3. 配置准备

  • 检查Redis配置

    bash
    # 查看RDB文件路径配置
    redis-cli config get dir
    redis-cli config get dbfilename
    
    # 或查看配置文件
    grep -E 'dir|dbfilename' /etc/redis/redis.conf
  • 修改Redis配置(如果需要):

    txt
    # 修改RDB文件路径
    dir /var/lib/redis
    
    # 修改RDB文件名
    dbfilename dump.rdb
    
    # 禁用AOF(如果只使用RDB恢复)
    appendonly no

恢复步骤

1. 单实例Redis恢复

步骤1:复制RDB文件到数据目录

bash
# 复制备份的RDB文件到Redis数据目录
cp /backup/redis/dump-20230901.rdb /var/lib/redis/dump.rdb

# 设置正确的权限
chown redis:redis /var/lib/redis/dump.rdb
chmod 644 /var/lib/redis/dump.rdb

步骤2:启动Redis服务

bash
# 使用systemd启动
systemctl start redis

# 或手动启动
redis-server /etc/redis/redis.conf

步骤3:验证恢复结果

bash
# 检查Redis是否正常运行
redis-cli ping

# 检查数据量
redis-cli dbsize

# 检查关键数据
redis-cli get <key>
redis-cli lrange <list-key> 0 10

2. 主从复制恢复

场景1:恢复整个主从集群

  1. 恢复主节点

    bash
    # 停止所有从节点
    for slave in <slave1-ip> <slave2-ip>; do
      redis-cli -h $slave -p 6379 shutdown
    done
    
    # 恢复主节点(参考单实例恢复步骤)
    cp /backup/redis/dump-20230901.rdb /var/lib/redis/dump.rdb
    systemctl start redis-master
    
    # 启动所有从节点
    for slave in <slave1-ip> <slave2-ip>; do
      ssh $slave "systemctl start redis-slave"
    done
  2. 验证主从关系

    bash
    # 检查主节点状态
    redis-cli -h <master-ip> info replication
    
    # 检查从节点状态
    redis-cli -h <slave-ip> info replication

场景2:仅恢复从节点

  1. 停止从节点

    bash
    redis-cli -h <slave-ip> -p 6379 shutdown
  2. 恢复从节点

    bash
    # 复制主节点的RDB文件到从节点
    scp <master-ip>:/var/lib/redis/dump.rdb /var/lib/redis/
    chown redis:redis /var/lib/redis/dump.rdb
    
    # 启动从节点
    systemctl start redis-slave
  3. 验证从节点状态

    bash
    redis-cli -h <slave-ip> info replication

3. Redis Cluster恢复

场景1:恢复单个节点

  1. 识别目标节点

    bash
    # 查看集群节点信息
    redis-cli -c cluster nodes | grep <node-ip>
  2. 停止目标节点

    bash
    redis-cli -h <node-ip> -p 6379 shutdown
  3. 恢复节点数据

    bash
    # 复制对应的RDB文件到节点数据目录
    cp /backup/redis/cluster-node1-dump.rdb /var/lib/redis/dump.rdb
    chown redis:redis /var/lib/redis/dump.rdb
    
    # 启动节点
    systemctl start redis-cluster-node1
  4. 验证节点状态

    bash
    redis-cli -c -h <node-ip> cluster info
    redis-cli -c -h <node-ip> cluster nodes | grep <node-ip>

场景2:恢复整个集群

  1. 停止所有集群节点

    bash
    for node in <node1-ip> <node2-ip> <node3-ip> <node4-ip> <node5-ip> <node6-ip>; do
      redis-cli -h $node -p 6379 shutdown
    done
  2. 恢复每个节点的数据

    bash
    # 为每个节点复制对应的RDB文件
    for i in {1..6}; do
      node_ip="node${i}-ip"
      cp /backup/redis/cluster-node${i}-dump.rdb /var/lib/redis/node${i}/dump.rdb
      chown -R redis:redis /var/lib/redis/node${i}
    done
  3. 启动所有集群节点

    bash
    for i in {1..6}; do
      systemctl start redis-cluster-node${i}
    done
  4. 验证集群状态

    bash
    redis-cli -c cluster info
    redis-cli -c cluster nodes
    redis-cli -c cluster slots
  5. 如果需要,重建集群(仅当集群配置丢失时):

    bash
    redis-cli --cluster create <node1-ip>:6379 <node2-ip>:6379 <node3-ip>:6379 <node4-ip>:6379 <node5-ip>:6379 <node6-ip>:6379 --cluster-replicas 1

RDB恢复验证

1. 数据完整性验证

  • 检查数据量

    bash
    # 恢复前后数据量对比
    echo "恢复前数据量: $(cat pre-recovery-dbsize.txt)"
    echo "恢复后数据量: $(redis-cli dbsize)"
  • 抽样检查关键数据

    bash
    # 检查关键业务数据
    redis-cli get "business:key1"
    redis-cli lrange "business:list1" 0 10
    redis-cli hgetall "business:hash1"
  • 检查过期键

    bash
    # 检查过期键数量
    redis-cli info keyspace | grep expires
    
    # 检查特定过期键
    redis-cli ttl "key-with-expire"

2. 性能验证

  • 检查内存使用

    bash
    redis-cli info memory | grep used_memory
  • 检查命令执行速度

    bash
    redis-cli info stats | grep instantaneous_ops_per_sec
  • 运行性能测试

    bash
    redis-benchmark -c 100 -n 100000 -t set,get,incr

3. 功能验证

  • 测试基本命令

    bash
    redis-cli set test-key test-value
    redis-cli get test-key
    redis-cli incr counter
    redis-cli del test-key counter
  • 测试数据结构

    bash
    # 测试List
    redis-cli lpush list-test 1 2 3
    redis-cli lrange list-test 0 -1
    
    # 测试Hash
    redis-cli hset hash-test field1 value1 field2 value2
    redis-cli hgetall hash-test
    
    # 测试Set
    redis-cli sadd set-test 1 2 3
    redis-cli smembers set-test
    
    # 测试Sorted Set
    redis-cli zadd zset-test 1 member1 2 member2 3 member3
    redis-cli zrange zset-test 0 -1 withscores

RDB恢复最佳实践

1. 备份策略

  • 定期备份

    bash
    # 设置cron任务,每天凌晨2点执行RDB备份
    0 2 * * * redis-cli bgsave && cp /var/lib/redis/dump.rdb /backup/redis/dump-$(date +%Y%m%d).rdb
  • 多版本备份

    bash
    # 保留最近7天的备份
    find /backup/redis -name "dump-*.rdb" -mtime +7 -delete
  • 异地备份

    bash
    # 将备份同步到异地服务器
    rsync -avz /backup/redis/ <remote-server>:/backup/redis/

2. 恢复准备

  • 预测试恢复流程

    bash
    # 在测试环境定期测试恢复流程
    cp /backup/redis/dump-$(date +%Y%m%d).rdb /test/redis/dump.rdb
    redis-server --dbfilename dump.rdb --dir /test/redis/ --port 6380
    redis-cli -p 6380 ping
    redis-cli -p 6380 dbsize
    redis-cli -p 6380 shutdown
  • 文档化恢复流程

    • 编写详细的恢复操作手册
    • 包括备份位置、恢复步骤、验证方法
    • 定期更新文档

3. 恢复操作

  • 选择合适的恢复时间

    • 业务低峰期
    • 有足够的时间进行恢复和验证
    • 相关团队人员可参与
  • 监控恢复过程

    bash
    # 查看Redis日志,监控恢复进度
    tail -f /var/log/redis/redis-server.log
  • 设置合理的超时时间

    bash
    # 对于大数据量恢复,增加超时时间
    redis-cli --timeout 60000 ping

4. 恢复后处理

  • 更新备份

    bash
    # 恢复完成后,立即创建新的备份
    redis-cli bgsave && cp /var/lib/redis/dump.rdb /backup/redis/dump-after-recovery-$(date +%Y%m%d%H%M%S).rdb
  • 清理临时文件

    bash
    # 清理恢复过程中产生的临时文件
    rm -f /tmp/redis-recovery-*.rdb
  • 通知相关团队

    • 恢复完成后,通知开发、测试和业务团队
    • 确认应用正常运行

常见问题(FAQ)

Q1: RDB文件损坏怎么办?

A1: 如果RDB文件损坏,可以尝试以下方法:

  1. 使用备份的RDB文件
  2. 使用redis-check-rdb工具修复:
    bash
    redis-check-rdb --fix /var/lib/redis/dump.rdb
  3. 如果无法修复,考虑使用AOF文件恢复(如果启用了AOF)
  4. 从主节点或其他从节点复制RDB文件

Q2: 恢复过程中Redis无法启动怎么办?

A2: 无法启动的原因及解决方法:

  1. RDB文件损坏:使用redis-check-rdb检查并修复
  2. 权限问题:确保RDB文件权限正确(redis:redis 644)
  3. 配置错误:检查redis.conf中的dir和dbfilename配置
  4. 内存不足:增加系统内存或调整Redis的maxmemory配置
  5. 版本不兼容:确保RDB文件与Redis版本兼容

Q3: 恢复后数据量不一致怎么办?

A3: 数据量不一致的原因及解决方法:

  1. 备份文件不完整:使用完整的备份文件重新恢复
  2. 过期键自动删除:检查过期键数量,过期键会在恢复后自动删除
  3. 数据类型不匹配:检查数据类型是否正确
  4. 部分数据丢失:考虑使用AOF文件进行补充恢复

Q4: 恢复后性能下降怎么办?

A4: 恢复后性能下降的解决方法:

  1. 内存碎片:重启Redis实例,重建内存分配
  2. 缓存预热:逐步访问热点数据,重建缓存
  3. 配置优化:调整Redis配置,如maxmemory-policy、hash-max-ziplist-entries等
  4. 硬件升级:增加内存或CPU资源

Q5: 如何恢复特定时间点的RDB备份?

A5: 恢复特定时间点备份的方法:

  1. 标识备份文件:备份时使用时间戳命名,如dump-202309011430.rdb
  2. 选择目标备份:根据时间点选择对应的RDB文件
  3. 恢复操作:按照恢复步骤使用选定的RDB文件进行恢复
  4. 验证数据:恢复后验证数据是否符合预期

Q6: 主从复制环境下,如何确保从节点与主节点数据一致?

A6: 确保主从数据一致的方法:

  1. 使用同一RDB文件:主从节点使用相同的RDB文件进行恢复
  2. 验证主从同步:恢复后检查主从复制状态
  3. 设置合适的同步参数:调整repl-backlog-size、repl-timeout等配置
  4. 监控复制延迟:定期检查主从复制偏移量差异

Q7: Redis Cluster恢复后槽分配错误怎么办?

A7: 槽分配错误的解决方法:

  1. 检查槽分配
    bash
    redis-cli -c cluster slots
  2. 手动修复槽分配
    bash
    # 将槽1000分配给节点node-id
    redis-cli -c cluster addslots 1000
    redis-cli -c cluster setslot 1000 node <node-id>
  3. 重建集群(如果问题严重):
    bash
    redis-cli --cluster create <node1>:6379 <node2>:6379 <node3>:6379 --cluster-replicas 1

Q8: 如何在不停机的情况下恢复RDB数据?

A8: 不停机恢复的方法:

  1. 使用从节点恢复:在从节点上恢复,然后切换为主节点
  2. 使用Redis Cluster:恢复单个节点,集群会自动处理
  3. 使用外部工具:如Redis-Shake、Redis-Migrate-Tool等
  4. 渐进式恢复:将RDB数据分批导入到运行中的Redis实例

Q9: RDB恢复和AOF恢复可以结合使用吗?

A9: 是的,可以结合使用:

  1. 先恢复RDB:快速恢复大部分数据
  2. 再恢复AOF:补充RDB之后的数据
  3. 配置混合持久化
    txt
    aof-use-rdb-preamble yes
  4. 手动结合
    bash
    # 先恢复RDB
    cp dump.rdb /var/lib/redis/
    # 再恢复AOF
    cp appendonly.aof /var/lib/redis/
    # 启动Redis
    redis-server --appendonly yes

Q10: 如何优化RDB恢复速度?

A10: 优化RDB恢复速度的方法:

  1. 使用更快的存储介质:如SSD
  2. 减少RDB文件大小
    • 启用RDB压缩:rdbcompression yes
    • 优化数据结构,减少内存占用
  3. 调整Redis配置
    • 增加repl-backlog-size
    • 调整hash-max-ziplist-entries等内存优化参数
  4. 使用多线程恢复(Redis 7.0+):
    txt
    io-threads 4
    io-threads-do-reads yes