AOF重写是用当前内存数据状态生成精简等效命令序列,不读旧AOF、只保留键终态,剔除冗余无效指令;通过子进程遍历有效key、按类型生成最简命令实现“逻辑重建”,并依赖auto-aof-rewrite-percentage与min-size协同触发。

AOF重写不是“删日志”,而是用当前内存数据状态,重新生成一套更精简的等效命令序列。它不读旧AOF文件,也不依赖历史操作,只看此刻Redis里真正存在的键值对和它们的最终状态——比如一个key被反复SET了10次,重写后只保留最后一次的SET命令;一个list被多次LPUSH,重写后合并成单条LPUSH带多个元素;已过期且被清理的key,直接不写入新文件。这样就把冗余、无效、中间态的指令全部剔除,让AOF体积大幅回落,接近实际内存数据的序列化大小。
重写怎么做到“瘦身”而不丢数据
重写过程本质是一次“逻辑重建”:
- 子进程fork后,遍历当前数据库所有有效key,跳过已过期、被删除、或未触发惰性删除的僵尸key(前提是maxmemory-policy不是noeviction)
- 对每个key,按类型生成最简命令:string用SET、hash用HMSET、list用LPUSH+多参数、set用SADD+多成员
- 忽略重复操作、中间状态、DEL之后又SET的组合,只保留终态
- 若启用混合持久化(aof-use-rdb-preamble yes),前半部分直接写RDB二进制快照,体积比纯文本AOF小50%以上
为什么光手动执行BGREWRITEAOF不够
手动重写只是单次“急救”,不能解决持续膨胀问题:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 重写完成后,新AOF仍会随业务写入不断追加,几天内就恢复原状
- 旧AOF文件不会自动删除,需等待原子替换完成才由主进程清理
- 若未配置自动触发参数,下一次重写永远不会发生
- 常见误判:看到aof_current_size从128GB降到22GB就以为搞定——其实这只是起点,不是终点
两个关键参数必须协同生效
auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 是“与”关系,缺一不可:
立即学习“Java免费学习笔记(深入)”;
- 前者控制增长比例(如设为80,表示比上次重写后的基线大80%就满足条件)
- 后者是绝对门槛(如aof_base_size是500MB,就设1gb,防止小增长就频繁重写)
- 举例:基线500MB,percentage=80,min-size=1gb → 必须同时满足“当前AOF ≥ 900MB”且“≥ 500MB×1.8 = 900MB”,才会触发
- 设错后果明显:min-size太小(如64MB)→ 小实例天天重写;min-size太大(如10GB)→ 大实例涨到30GB也不动
重写期间磁盘空间怎么算才安全
重写不是覆盖,而是“双文件共存”:
- 主进程继续往旧AOF追加新命令,子进程同步写新AOF文件
- 峰值磁盘占用 ≈ 当前AOF大小 + 新AOF大小(新文件≈内存数据序列化体积,通常为旧文件的20%~50%)
- 保守估算:空闲空间至少留出当前AOF大小的1.5倍;推荐2倍,尤其当aof_current_size超5GB时
- 务必检查dir路径挂载点,避免和其他服务混用分区

















