AOF重写导致%util接近100%的根本原因是主线程与子进程双路IO竞争同一磁盘设备,引发队列堆积和await升高;需通过开启aof-rewrite-incremental-fsync打散刷盘节奏、合理配置no-appendfsync-on-rewrite及检查底层存储语义来缓解。

Redis 6.0 中 AOF 重写打满磁盘 IO,核心不是“要不要关重写”,而是必须隔离写入流、打散刷盘节奏、并确认底层存储语义是否支持。
为什么 AOF 重写会让 iostat 的 %util 接近 100%
重写由子进程执行,主线程仍持续追加新命令到旧 AOF 文件,两者同时向同一块设备写入:主线程按 appendfsync 策略刷盘(默认每秒一次),子进程批量生成新 AOF 文件(默认攒够 32MB 才调一次 fdatasync)。当磁盘 IOPS 或带宽见顶,IO 队列堆积,await 升高,redis_aof_delayed_fsync 持续非零——这不是 Redis 卡住,是磁盘真的吞不下。
常见误判:只看 CPU 和内存正常就认为没问题;实际 iostat -x 1 中 %util > 95% 或 await > 20ms 就已是明确瓶颈信号。
- SSD 也不能免疫:若 AOF 文件和系统日志共用同一 NVMe 设备,或挂载时启用了
barrier=1或sync参数,照样会拖慢 - 云环境特别容易踩坑:低配 EBS、NFS 卷、或 K8s PVC 后端不支持
rename()原子操作,会导致重写卡在临时文件阶段,IO 持续占用不释放 - 检查是否真在重写:
redis-cli INFO persistence | grep aof_rewrite_in_progress返回 1 才是正在重写;若为 0 但 IO 仍高,问题不在重写本身
必须开启 aof-rewrite-incremental-fsync
这是 Redis 6.0 默认启用但常被忽略的关键开关。它让子进程不再攒大块再刷盘,而是每写入 4MB 就调一次 fdatasync,把单次 32MB 的 IO 峰值打散成 8 次小 IO,显著降低瞬时压力。
实操建议:
- 确认当前状态:
redis-cli CONFIG GET aof-rewrite-incremental-fsync,返回"yes"才生效 - 若磁盘仍吃紧,可调大批次:例如
CONFIG SET aof-rewrite-incremental-fsync 8388608(即 8MB),但该配置需写入redis.conf并重启才永久生效 - 注意:此参数只影响子进程,不影响主线程的
appendfsync行为,无需担心一致性风险
no-appendfsync-on-rewrite yes 要慎用,但生产环境往往不得不开
开启后,AOF 重写期间主线程停止 fsync,仅靠内核脏页回写机制落盘。这能立刻缓解 IO 竞争,但代价是:若此时 Redis 崩溃,最多丢失重写开始后 1 秒(everysec)+ 重写期间所有新写入的数据。
适用前提:
-
appendfsync必须是everysec(always下该配置无效) - 业务能接受秒级数据丢失(金融强一致场景禁用)
- 已通过
CONFIG SET no-appendfsync-on-rewrite yes开启,并监控aof_rewrite_in_progress避免重写长时间卡住 - 必须配合
auto-aof-rewrite-percentage和auto-aof-rewrite-min-size合理设置,否则重写太频繁,窗口期丢失风险放大
磁盘路径与挂载参数比 Redis 配置更关键
很多团队换了 NVMe 盘仍 IO 打满,最后发现是权限或挂载参数锁死了性能。Redis 6.0 对 rename() 原子性依赖更强(重写完成时用它替换原 AOF 文件),而 NFSv3、某些 CephFS 后端、或未配 fsGroup 的 K8s PVC 都不保证这点,导致重写失败或卡住。
排查要点:
- 确认
dir和appendfilename在同一挂载点:df /var/lib/redis和df /var/lib/redis/appendonly.aof输出应一致 - 检查挂载选项:
mount | grep redis,理想是noatime,data=writeback;避免sync、barrier=1、journal=ordered - 容器环境重点查:
securityContext.fsGroup: 999(匹配 redis 用户 UID),并在容器内运行touch /data/test && mv test test2验证rename是否成功 - 裸盘写速测试:
time dd if=/dev/zero of=/path/to/redis/data/test bs=4k count=10000 oflag=direct,低于 5MB/s 基本可判定硬件或驱动层瓶颈
最容易被忽略的是:AOF 重写完成后的原子替换动作,它不依赖 Redis 逻辑,而直击文件系统语义。一旦这里失败,临时文件残留、IO 持续占用、磁盘空间无法释放——问题就从“性能”滑向“可用性”。


















