Redis 误操作数据恢复

Redis 误操作数据恢复

误操作的常见场景

在生产环境中,Redis 误操作可能发生在多个环节:

误操作类型 示例 后果
误删 key DEL important_key 关键数据丢失
误删库 FLUSHDB / FLUSHALL 当前/所有数据库清空
误覆盖 SET key wrong_value 正确数据被覆盖
误过期 EXPIRE key 0 / 设错 TTL key 被立即/提前删除
误替换 误替换了数据结构 List/Hash/Set 数据被覆盖

恢复策略概览

误操作发生
  ↓
判断操作类型
  ├── 数据被删(DEL/FLUSH)
  │   ├── AOF 仍保留命令?→ 从 AOF 恢复
  │   ├── 有 RDB 快照?→ 回到快照时间点
  │   └── 有备份?→ 从备份恢复
  │
  ├── 数据被覆盖(SET/HSET)
  │   ├── AOF 有记录?→ 可以精确恢复
  │   └── 无记录?→ 只能回滚到备份点
  │
  └── 大量数据丢失
      ├── 从备份 RDB 恢复到新实例
      └── 使用 diff 工具找出差异数据

方法一:AOF 日志恢复(最精确)

原理

如果开启了 AOF,所有写操作都以 Redis 协议格式记录在 AOF 文件中。可以通过编辑 AOF 文件,删除误操作的命令,然后重放。

恢复流程

# 场景:误执行了 FLUSHALL

# Step 1: 立即停止 Redis 避免数据被覆盖
redis-cli SHUTDOWN NOSAVE

# Step 2: 备份当前的 AOF 文件
cp /var/lib/redis/appendonly.aof /backup/appendonly_before_flush.aof

# Step 3: 从 AOF 中删除 FLUSHALL 命令
# FLUSHALL 在 AOF 中的记录
*1
$8
FLUSHALL

# 使用工具移除
redis-check-aof --fix-remove-cmd "FLUSHALL" appendonly.aof
# 或者手动编辑:
grep -v "FLUSHALL" appendonly.aof > appendonly_clean.aof

注意:AOF 重写后 FLUSHALL 命令就不在了(被合并到新的基础快照中)。所以误操作后要立即处理。

恢复单条 DEL 命令

# 场景:误 DEL 了某个关键 key

# Step 1: 停止 Redis,备份 AOF
redis-cli SHUTDOWN
cp appendonly.aof appendonly.aof.bak

# Step 2: 在 AOF 中找到误操作的命令
# AOF 记录格式(协议文本模式):
*1
$3
DEL
$5
mykey

# Step 3: 删除该命令,可以精准恢复
# 使用 Python 脚本
python3 << 'EOF'
import re

aof_file = "/var/lib/redis/appendonly.aof"
target_cmd = b"*1\n$3\nDEL\n$5\nmykey\n"

with open(aof_file, "rb") as f:
    content = f.read()

# 删除目标命令
new_content = content.replace(target_cmd, b"")

with open(aof_file + ".fixed", "wb") as f:
    f.write(new_content)

print(f"原始大小: {len(content)} bytes")
print(f"修复后大小: {len(new_content)} bytes")
print(f"AOF 修复完成: {aof_file}.fixed")
EOF

方法二:RDB 快照恢复

恢复到快照时间点

# 场景:误操作 30 分钟,最近一次 RDB 快照是 1 小时前

# Step 1: 使用 RDB 备份恢复到新实例
redis-server --port 6380 --dbfilename dump_backup.rdb \
             --dir /tmp --daemonize yes

# Step 2: 比较数据差异
# 导出原始数据
redis-cli -p 6379 KEYS "*" > /tmp/keys_current.txt
redis-cli -p 6380 KEYS "*" > /tmp/keys_backup.txt

# 找出丢失的 key
diff /tmp/keys_current.txt /tmp/keys_backup.txt | grep "^>" | cut -d' ' -f2 > /tmp/missing_keys.txt

# Step 3: 从备份实例逐个恢复丢失的 key
cat /tmp/missing_keys.txt | while read key; do
    type=$(redis-cli -p 6380 TYPE "$key")
    case $type in
        string)
            val=$(redis-cli -p 6380 GET "$key")
            redis-cli -p 6379 SET "$key" "$val"
            ;;
        hash)
            redis-cli -p 6380 HGETALL "$key" | xargs redis-cli -p 6379 HMSET "$key"
            ;;
        list)
            redis-cli -p 6380 LRANGE "$key" 0 -1 | tac | sed '1~2d' | xargs -I {} redis-cli -p 6379 RPUSH "$key" {}
            ;;
        set)
            redis-cli -p 6380 SMEMBERS "$key" | xargs redis-cli -p 6379 SADD "$key"
            ;;
        zset)
            redis-cli -p 6380 ZRANGE "$key" 0 -1 WITHSCORES | xargs redis-cli -p 6379 ZADD "$key"
            ;;
    esac
    echo "已恢复: $key"
done

方法三:利用主从复制恢复

如果误操作时主从架构运转正常:

# 场景:在主库误操作,从库还未同步

# Step 1: 立即在从库执行 SLAVEOF NO ONE
redis-cli -p 6380 SLAVEOF NO ONE

# Step 2: 从从库导出被删除的数据(如果有)
# 注意:如果从库已经复制了误操作命令,此方法无效

# Step 3: 恢复主库
redis-cli -p 6380 BGSAVE  # 从库生成快照
# 将 RDB 文件传到主库
# 重启主库加载该 RDB

预防误操作的最佳实践

1. 使用 RENAME 重命名危险命令

# redis.conf
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command DEL "safe_del"
rename-command KEYS "safe_keys"

2. 设置操作确认(通过 Lua 脚本)

-- 实现一个"安全 DEL",需要二次确认
local key = KEYS[1]
local confirm = ARGV[1]

if confirm ~= "YES_I_AM_SURE" then
    return "ERROR: 请确认删除操作,使用 YES_I_AM_SURE 确认"
end

return redis.call("DEL", key)

3. 使用 Redis 6.0+ ACL 权限控制

# 创建只读用户(避免误操作)
redis-cli ACL SETUSER readonly_user on >password +@read ~*

# 创建有写权限但无危险命令的用户
redis-cli ACL SETUSER normal_user on >password +@write -@dangerous ~*

# 普通开发人员使用 readonly_user

4. 延迟执行的”回收站”机制

-- 带回收站的删除
local key = KEYS[1]
local ttl = tonumber(ARGV[1]) or 86400  -- 默认保留1天

-- 重命名 key 并设置过期(相当于移到回收站)
local trash_key = "trash:" .. key
redis.call("RENAME", key, trash_key)
redis.call("EXPIRE", trash_key, ttl)

return 1

恢复速查表

误操作 恢复方法 恢复精度 恢复时间
DEL 单个 key AOF 移除 DEL 命令 秒级 分钟级
FLUSHALL AOF 移除 FLUSHALL 秒级 分钟级
SET 覆盖值 AOF 中删除 SET 秒级 分钟级
批量 DEL RDB 恢复 + diff 小时级 分钟级
无备份误删 无法恢复
过期 key 无法恢复

面试要点

  • 黄金第一原则:误操作后立即停止 Redis(或停写操作)
  • AOF 是救命稻草:只要没执行 BGREWRITEAOF,AOF 还保留着命令
  • RDB 兜底:即使 AOF 不可用,RDB 快照是最后的防线
  • 预防>恢复:RENAME 危险命令、使用 ACL、定期备份
  • TTL 数据不可恢复:过期 key 一旦删除无法通过 AOF 恢复
  • 主从方案:误操作后立即 SLAVEOF NO ONE 隔离从库
© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容