开启no-appendfsync-on-rewrite yes可缓解aof重写期间的磁盘i/o争抢,仅在appendfsync everysec下生效,但无法解决写时复制导致的内存与系统调用开销。

开启 no-appendfsync-on-rewrite yes 能显著缓解 AOF 重写期间的磁盘 I/O 剧增,但仅在 appendfsync everysec 模式下生效,且不能解决写时复制(COW)导致的内存与系统调用开销。
为什么 AOF 重写会触发磁盘 I/O 剧增
根本原因不是子进程在“写新文件”本身慢,而是父子进程同时刷盘:父进程按 everysec 策略每秒调用 fsync(),子进程重写时也在持续 write() 临时 AOF 文件。两者共用同一块磁盘(尤其是机械盘或混用分区),I/O 队列迅速堆积,Asynchronous AOF fsync is taking too long 日志频繁出现,进而拖慢主线程响应。
典型表现包括:redis-cli --latency 出现毫秒级毛刺、监控中 used_memory_rss 在重写开始后快速上涨、INFO persistence 显示 aof_buffer_length 长期 >1MB。
- 子进程写临时文件 + 父进程每秒
fsync()→ 双重 I/O 压力 - 若 AOF 文件和系统日志、RDB 或其他服务共用一块 HDD,争抢更剧烈
-
auto-aof-rewrite-percentage设得过低(如 30)会导致重写太频繁,I/O 毛刺常态化
no-appendfsync-on-rewrite 的真实作用与限制
这个配置不是“关掉父进程的 AOF 写入”,而是让父进程在重写进行中跳过 fsync() 调用,只做 write() 到内核 page cache,等重写结束后再恢复每秒刷盘。它缓解的是 I/O 调度冲突,不是内存拷贝或 fork 开销。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 仅对
appendfsync everysec生效;always下强制同步,no下本就不刷盘 - 启用后,极端宕机场景最多丢失 2 秒数据(上一个
everysec周期 + 当前重写期间未刷盘部分) - 不会降低
used_memory_rss上涨速度,也不能阻止 COW 导致的延迟升高 - 必须配合
vm.overcommit_memory=1,否则fork()可能失败,重写直接卡住
比 no-appendfsync-on-rewrite 更关键的实操动作
很多人开了这个参数就以为问题解决,但实际线上卡顿往往来自更底层的协同问题:
- 启用
aof-rewrite-incremental-fsync yes:默认子进程攒够 32MB 才fdatasync()一次,改成增量刷盘(每 32KB 就同步),避免单次 I/O 峰值打爆队列 - 把
appendfilename指向独立 SSD 分区,和 RDB、系统日志物理隔离 - 禁止重写期间执行
BGREWRITEAOF或BGSAVE—— 多个 fork 叠加会让 COW 和内存压力翻倍 - 调大
aof-rewrite-min-size(如从 64mb 改为 256mb),减少小文件重写频次,尤其适用于日增 AOF 超 1GB 的业务
怎么确认优化真正起效
不能只看配置是否写进 redis.conf,得盯住三个指标:
- 用
redis-cli INFO persistence观察aof_rewrite_in_progress为 1 时,aof_buffer_length是否不再持续 >512KB - 用
cat /proc/$(pidof redis-server)/status | grep VmRSS对比重写前后 RSS 增速是否变平缓 - 临时跑
strace -p $(pidof redis-server) -e trace=fsync -T 2>&1 | grep fsync(仅调试),确认重写期间fsync()调用频率是否归零(注意:勿长期运行)
重写慢从来不是单一环节的问题,是内存分配、页表拷贝、磁盘调度、内核参数和 Redis 配置共同耦合的结果。调一个参数容易,但漏掉 vm.overcommit_memory 或混用磁盘,再好的配置也白搭。










