redis qps断崖下跌主因是appendfsync always导致主线程被fsync阻塞,aof_delayed_fsync和aof_pending_bio_fsync非零即证实刷盘滞后,iostat与iotop可验证i/o瓶颈,必须开启no-appendfsync-on-rewrite yes防重写雪崩。

Redis QPS断崖下跌,先盯aof_delayed_fsync和aof_pending_bio_fsync
这不是配置写错了,而是appendfsync always把主线程死死绑在磁盘上。只要这两个指标非零,就说明fsync已经开始排队——aof_delayed_fsync持续上涨,代表后台刷盘线程已滞后;aof_pending_bio_fsync不为0,说明内核bio队列里还压着没落盘的AOF缓冲区。
常见错误现象:redis-cli --latency显示P99延迟跳到20–50ms;INFO persistence里aof_delayed_fsync每秒涨几十甚至上百;日志反复出现Asynchronous AOF fsync is taking too long。
别急着调参数,先用命令确认:
redis-cli info persistence | grep -E "aof_delayed_fsync|aof_pending_bio_fsync"-
iostat -x 1看%util是否长期100%、await是否>10ms、w/s是否卡在磁盘IOPS极限(机械盘≈150,SATA SSD≈3000) -
iotop -o -a过滤redis-server,看WRITE列是否稳定在几百KB/s——这是被fsync反复掐住脖子的典型特征
为什么appendfsync always会让QPS被钉死在磁盘IOPS上
因为每次SET、INCR执行完,Redis主线程必须调用fsync()等硬件确认落盘才返回客户端。这个系统调用不是“发个指令就完”,而是同步阻塞,直到磁盘控制器返回完成信号。
SSD单次fsync()平均耗时0.2–1ms,但高并发下请求排队,延迟直接叠加。实测中,10万QPS写入下,always模式常只剩2–3万QPS,本质是被磁盘随机写IOPS卡死了。
注意几个关键点:
- 即使挂NVMe SSD,若AOF文件放在
ext4且未启用data=writeback挂载选项,fsync()仍要等journal落盘,性能打七折 -
top里CPU占用可能很低,但I/O早已满负荷——别只看CPU - 云盘标称IOPS是理论峰值,实际受IO调度器、队列深度影响,往往只有6–8折
no-appendfsync-on-rewrite yes不是可选项,是必开项
AOF重写(bgrewriteaof)会fork子进程,此时若同时开启appendfsync always,主线程的write()和子进程的磁盘读取会激烈争抢I/O带宽,导致主线程write被阻塞,QPS瞬间归零。
这个配置不是“锦上添花”,而是防止雪崩的底线操作:
- 必须设为
yes,否则重写期间主线程刷盘会被强制暂停,积压缓冲区暴涨 - 代价是重写窗口期最多丢失1秒数据(与
everysec一致),但避免了QPS断崖 - 配合
aof-use-rdb-preamble yes使用,能加速重启加载,避免AOF回放慢成瓶颈
别迷信always,真要零丢失得靠架构兜底
appendfsync always解决不了原子性问题:它保证命令落盘,但不保证主从同步、不防进程崩溃前最后一刻的内核缓冲区丢失、更不防应用层重复提交。
真正需要强一致的场景(如库存扣减),单靠always是危险的:
- 应搭配双写+幂等+下游服务自愈能力
- 缓存类、排行榜、实时统计等数据,丢了可重建,关AOF或切
everysec反而更稳 - 如果磁盘
await持续>5ms且%util≥95%,always已无实际意义——你不是在保数据,是在给磁盘打工
最常被忽略的一点:AOF重写失败时的fork: Cannot allocate memory错误,往往不是内存不够,而是vm.overcommit_memory设为0且碎片率>1.5。这个细节一漏,所有优化都白搭。











