AOF暴增源于其按协议原样追加写命令的设计,不感知语义、不合并操作;重写需同时满足auto-aof-rewrite-percentage和auto-aof-rewrite-min-size,且依赖真实写入触发;BGREWRITEAOF fork子进程生成新文件,需双倍磁盘空间与额外内存。
因为AOF不是存数据快照,而是逐条记录所有写命令——哪怕一个key被覆盖100次,它就记100行;哪怕一次LPUSH塞5个元素,它就拆成5条命令追加。这不是bug,是设计使然。
AOF按协议格式原样追加命令文本,不感知语义,也不做合并。比如对同一个counter执行1000次INCR,AOF里就是1000行*2rn$4rnINCRrn$7rncounter;而LPUSH list a b c d e在AOF中实际被拆解为5条独立LPUSH命令。
EXPIRE/DEL类命令也会被记录,即使对应key后续已不存在,它们仍占空间这两个参数必须同时满足才触发重写,但很多人配了却没反应,核心原因是:aof_current_size初始为0,且Redis只在有真实写入后才开始计算增长百分比。
SET a b都没有),aof_current_size始终是0,百分比无意义redis.conf里,但运行时没执行CONFIG REWRITE,重启后就丢失auto-aof-rewrite-min-size设太小(如16mb)会导致即使增长200%,因未达下限也不触发CONFIG GET auto-aof-rewrite*,别只看配置文件BGREWRITEAOF不是复制粘贴,而是fork子进程遍历内存生成新AOF——这过程对资源有硬性要求。
appendonly.aof大小的2倍:旧文件继续追加,新文件同时生成Can't rewrite append only file: No space left on device,不是磁盘满,而是重写时临时空间不足no-appendfsync-on-rewrite yes,避免重写期间fsync加剧IO压力最易被忽略的一点:重写后AOF变小,不代表数据丢了——它只保留最终存活的key及其值,所有中间状态、已过期或已删除的key都不会进新文件。但这也意味着,如果你依赖AOF里某条EXPIRE命令的时间点做业务逻辑,那重写后这个信息就没了。