AOF文件越写越大是因为Redis将每个写命令追加到文件末尾且不自动删除或压缩历史命令;触发重写需同时满足auto-aof-rewrite-percentage和auto-aof-rewrite-min-size配置,并依赖写流量与appendonly yes开启。

为什么AOF文件会越写越大
AOF本质是把每个写命令追加到文件末尾,不删旧、不压缩,时间一长自然膨胀。Redis不会自动清理历史命令——比如SET key1 val1之后又SET key1 val2,AOF里两条都留着;再比如INCR counter执行1000次,AOF就记1000行。这不是bug,是设计使然:保证重放精确性。
真正触发重写的不是文件大小本身,而是配置项auto-aof-rewrite-percentage和auto-aof-rewrite-min-size共同作用的结果。前者是“当前AOF大小比上次重写后增长了多少百分比”,后者是“绝对下限”。两个条件必须同时满足才会触发BGREWRITEAOF。
如何让BGREWRITEAOF真正生效
很多人配了参数却没看到重写发生,核心原因是:Redis只在有“写流量”且“AOF已启用”时才检查是否该重写。如果实例刚启动、还没执行过任何写命令,或者appendonly no,那配置再对也没用。
-
appendonly yes必须开启,否则压根不生成AOF文件 - 确保至少有一次成功写入(哪怕只是
SET a b),否则aof_current_size为0,百分比计算失效 - 检查
CONFIG GET auto-aof-rewrite*确认实际加载的值,某些版本会忽略注释后的空格导致配置未生效 - 重写过程本身不阻塞主线程,但会fork子进程,内存不足或写时复制(COW)压力大会失败,日志里会出现
Can't rewrite append only file: No space left on device或Failed to fork
重写后AOF变小,但数据没丢?
重写不是简单去重,而是“读取当前内存快照 + 过滤冗余命令 + 生成最小等效指令集”。例如key被多次覆盖,只保留最后一次;list被LPUSH又LPOP,可能直接消失;甚至整个key被DEL掉,就不会出现在新AOF里。
但要注意:EXPIRE类命令不会被重写进新AOF——过期时间由Redis内部维护,重写只保留“最终存活的键值对”。所以重写后AOF更小,不代表丢了逻辑,只是去掉了中间态噪音。
重写完成前,老AOF继续追加;重写成功后,Redis原子替换文件名,并清空旧文件缓冲区。整个过程对客户端透明。
手动触发重写时的典型陷阱
执行BGREWRITEAOF命令看似简单,但容易卡住或失败:
- 如果正在执行
BGSAVE,BGREWRITEAOF会排队等待,直到BGSAVE结束——不是并行,是串行 - 如果磁盘满、inode耗尽、或父进程内存碎片严重,fork失败,命令返回
Background append only file rewriting started但实际没干活,得看INFO persistence里的aof_rewrite_in_progress是否为1 - 重写期间若发生崩溃,Redis仍可用老AOF恢复——新AOF是临时文件,只有rename成功才算落地
- 别在高峰期手动触发,fork子进程可能引发毫秒级延迟,尤其大内存实例(>10GB)
真正难的是判断“该不该重写”:有些业务写入极不规律,比如凌晨批量导入后AOF暴增,但白天几乎不写,这时自动策略可能永远不触发。得结合INFO persistence里的aof_base_size和aof_current_size手动盯盘。

















