西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页 → 业内动态 → 业内资讯 → Redis误删30万Key后不敢重启:AOF重写压回600M救场

Redis误删30万Key后不敢重启:AOF重写压回600M救场

相关软件相关文章发表评论 来源:本站整理时间:2026/11/2 23:15:09字体大小:A-A+

作者:xiix点击:3次评论:0次标签: Redis持久化 RDB快照 AOF重写 appendfsync Redis数据丢失

  • 类型:数据库类大小:93M语言:中文 评分:10.0
  • 标签:
立即下载

那天下午三点,一个跑了三年多的 Redis 实例被人误删了一批 key,业务反馈说缓存里的用户画像全没了。我第一反应是赶紧回滚,重启服务让它从持久化文件里把数据捞回来。结果重启之后才发现,数据照样是空的那份 appendonly.aof 里,那条 DEL 命令写得清清楚楚。也就是说,误删这个动作本身已经被忠实地记录进了持久化日志,重启不但救不了你,反而让这件事变成了板上钉钉的事实。

那次之后我们花了两天重做 Redis 的持久化方案,也顺手把主从、哨兵、自动重写的策略一起理了一遍。下面这些是我自己踩过的坑和后来沉淀下来的做法,不敢说最优,但至少每一条都是花钱买来的经验。如果你也在纠结 RDB 和 AOF 到底怎么配、appendfsync 三个档位差在哪、AOF 文件为什么越涨越大,这篇可能能帮你少走点弯路。

如果你要给 Redis 配持久化、又担心机器配置不够用,可以先看看这几家:RackNerd(全球 VPS 与大存储机型,硬盘给得足,适合跑缓存节点)、狗云DOGYUN(高性价比云服务器,机型齐全,适合多机部署哨兵)。

一、先说清楚:RDB 和 AOF 到底各自在做什么

RDB 是快照。在某个时间点,Redis 把内存里的数据集整个写成一个二进制文件 dump.rdb。写的过程是先把数据 fork 出一个子进程,子进程拿到写时复制之后的内存快照,再慢慢写到磁盘上。好处是文件小、恢复快一个 10G 内存的实例,rdb 可能只有 2G 多;坏处是两次快照之间的数据是纯丢失的,因为内存里那些还没落盘的修改,磁盘上压根没有记录。

AOF 是日志。它记录的是每一条写命令本身,比如 SET user:1001 {...}、DEL user:2002 这类,直接以文本形式追加写到 appendonly.aof 文件末尾。好处是只要写进去了就能还原,数据粒度比 RDB 细得多;坏处是文件会不断膨胀,同样一批数据,AOF 可能比 RDB 大好几倍,而且恢复速度也更慢,因为 Redis 需要一条一条重放命令。

用一个不太严谨但好理解的比喻:RDB 像定期拍照,AOF 像记流水账。拍照的文件小但会丢中间过程,流水账丢不了但会越写越厚。

运维工程师在监控面板前查看 Redis 持久化运行状态

二、appendfsync 的三个档位,是我最不建议随手乱设的地方

AOF 真正的关键不是开不开,而是 appendfsync 设成什么。它决定了操作系统多久把 AOF 缓冲区刷到磁盘上。官方文档给了三个值,实际含义差别很大。

always:每写一条命令就 fsync 一次。理论上除了断电(连硬盘缓存都没刷下去的情况)几乎不丢数据,代价是每条写命令都要等一次磁盘同步写入,QPS 直接被 IOPS 卡住。我们压测过一次,appendfsync always 下写入吞吐掉了两个数量级,从每秒十几万降到一千左右。这档只适合数据绝对不能碰、但写入量不大的场景,比如存 token、存验证码这类小而关键的东西。

everysec:每秒 fsync 一次。这是官方推荐值,也是我们最终选的。理论上最坏情况丢一秒的数据,实际丢的数据量取决于这一秒里有多少写命令;如果这一秒正好是业务高峰,可能丢的数据量不小,但换来的是性能相当能打。绝大多数业务场景,缓存丢一秒是可以接受的,因为缓存本来就是从数据库或者接口重新灌的。

no:交给操作系统自己决定什么时候刷盘,理论上最坏可能丢 OS 缓冲区里的全部数据,速度最快。这档我只在纯计算型、完全可以从别处重建的实例上用过,比如跑排行榜计算的临时 Redis。

dump.rdb 快照文件与 appendonly.aof 日志文件的对比

顺带一提,Redis 4.0 之后 AOF 文件头部是 RDB 格式,也就是常说的 aof-use-rdb-preamble,好处是文件更小、重写更快。所以你会发现同样一份数据,纯 AOF 的文件体积并不比 RDB 大太多,别被「AOF 一定大很多」这个说法误导。

三、AOF 越写越大怎么办:靠重写(BGREWRITEAOF)

这是我们踩得最疼的一个坑。前面那次误删事故后的排查过程里,我们发现 appendonly.aof 已经涨到了 8G 多,里面绝大部分是重复的 SET同一个 key 被反复更新了几万次,日志里就躺着几万条一模一样的赋值命令。机器磁盘本来就吃紧,那 8G 文件还直接拖慢了重启。

Redis 的解法是 AOF 重写:后台起一个子进程,把当前内存里的数据集重新写成一份最小的、只包含有效数据的命令序列,写完后原子替换掉原来的 AOF 文件。整个过程主进程照常服务,写命令会同时记进两个缓冲区,等重写完成后补齐。8G 的日志,最后被压到了 600 多 MB差距有多大,可见一斑。

重写是自动触发的,两个参数说了算:

auto-aof-rewrite-percentage:当前 AOF 文件大小 compared to 基准大小的百分比,默认 100,意思是文件比基准大一倍就触发重写。

auto-aof-rewrite-min-size:基准大小,默认 64MB。文件小于这个值时,哪怕百分比到了也不会触发这是为了避免小文件被反复重写。

我们的实际配置是 auto-aof-rewrite-percentage 100、auto-aof-rewrite-min-size 256mb,考虑到这台机器的写入量确实大,把基准抬高了,减少重写频率。

服务器异常重启导致数据丢失的风险场景示意

四、几个细节,每一个都真实咬过我

第一个是 no-appendfsync-on-rewrite。这个参数默认是 no,也就是重写期间主进程仍然照常 fsync AOF。代价是重写期间磁盘 IO 压力翻倍,机器负载会明显抬高;好处是这期间的数据不会因为重写而丢失。线上机器 IO 比较紧张的时候,可以把它设成 yes,重写期间用操作系统缓冲,重写完再 fsync 一次,中间这段数据有丢失风险。取舍看你的机器性能和业务容忍度,别照抄别人的配置。

第二个是 dir 和 dbfilename 的权限。如果 Redis 以普通用户跑,而 dir 指向的目录不可写,AOF 写入会直接失败,日志里报 "Permission denied",但 Redis 主进程并不会因此退出,它只是在那儿一边跑一边丢持久化。特别坑的是这时候服务完全正常,监控全绿,直到某天重启才炸。我现在的做法是给 Redis 单独开一个目录,owner 给 redis 用户,权限 750,同时把 dir 写死在一个绝对路径上,别用相对路径。

第三个是 save 指令和 RDB 的关系。很多人以为开了 AOF 就不用管 save 了,其实 save 是独立的,RDB 快照照旧按配置在跑。想彻底关掉 RDB,可以把 save "" 写进配置文件。但我建议留着 RDBAOF 损坏的时候,rdb 往往是能救命的备份。

第四个是持久化和过期键。Redis 判定一个键过期是惰性删除加定期采样,AOF 里对应的那条 SET 一直都在,键过期之后并不会往 AOF 里写 DEL。所以 AOF 文件会保留大量已经过期的键的赋值记录,这也是 AOF 越大的原因之一之一,重写的时候会把这些没用的记录清掉。

内存中的数据流持续写入磁盘的抽象示意

五、我们最后落地的一套配置

说完坑,给个可以直接抄的版本。我们的场景是:缓存为主(数据丢了能从库里重建),但里面有一部分关键的会话数据不能丢,所以实际上是两套 Redis。

纯缓存实例:appendonly no,save "900 1",maxmemory 2gb,maxmemory-policy allkeys-lru,dir /data/redis/,dbfilename dump.rdb,requirepass 设强密码,bind 只监听内网地址,protected-mode yes。

会话/关键数据实例:appendonly yes,appendfsync everysec,auto-aof-rewrite-percentage 100,auto-aof-rewrite-min-size 256mb,no-appendfsync-on-rewrite no,save "900 1 300 10 60 10000",maxmemory 4gb,maxmemory-policy noeviction,dir /data/redis-aof/。

再加一条运维上的硬规定:任何 flushall、flushdb、批量 DEL 的操作,必须走一个带审批的脚本,禁止直接在 redis-cli 里手敲。这一条比什么持久化策略都管用上次那 30 万个 key,根子不是没开 AOF,是有人执行了一条没加限制的批量删除,而且没走变更流程。

最后补一句关于副本和哨兵:主节点上的 AOF 写入压力本身不小,如果用的是哨兵模式,副本做 AOF 重写的时候,主从之间还可能触发一次全量同步,几百万 key 的实例这时候延迟会明显飘。想稳一点,可以考虑副本开 RDB 不开 AOF,或者用 replica-no-rewrite 适当控制一下节奏。反正这三个东西(持久化、副本、哨兵)凑在一起才是完整的高可用,单独调好一个没什么意义。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶顶
    • 1 难过难过
    • 5 囧囧
    • 3 围观围观
    • 2 无聊无聊

    发表评论

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲