appendfsync always直接卡主线程,因其每次写命令后必须同步阻塞等待fsync()完成,主线程无法处理后续请求;SSD单次耗时0.2–1ms,高并发下排队导致P99延迟飙升至20–50ms。

appendfsync always 为什么直接卡主线程
因为 appendfsync always 要求每次写命令执行完,立刻调用 fsync() 强制刷盘,而这个系统调用是同步阻塞的——主线程必须等磁盘返回确认,才能处理下一条命令。Redis 的事件循环(event loop)就卡在这儿了。
SSD 单次 fsync() 平均耗时 0.2–1ms,看似不多;但并发写入量一上来,请求就在主线程排队,P99 延迟很容易飙到 20–50ms,redis-cli --latency 会明显暴露这点。
关键不是 Redis 自身慢,是它把所有写请求都绑死在同一个 I/O 路径上。哪怕磁盘负载只有 40%,只要 fsync() 排队,主线程就停摆。
everysec 模式下 fsync 线程被阻塞的真实表现
appendfsync everysec 虽然用后台线程做 fsync(),但主线程仍要监控其进度:一旦发现上一次 fsync() 还没完成,新来的 write() 就会被挂起等待。
常见诱因是 AOF 重写(bgrewriteaof)和 fsync() 抢磁盘带宽。此时你会看到:
-
aof_delayed_fsync持续 > 0(INFO persistence 输出) -
aof_pending_bio_fsync不为零 - 日志出现
Asynchronous AOF fsync is taking too long - 磁盘 iowait 飙高,但 CPU 使用率不高
这不是配置错了,是磁盘 I/O 已成瓶颈,后台线程也救不了。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
no-appendfsync-on-rewrite yes 必须开,否则雪上加霜
当 AOF 重写进行中,如果 no-appendfsync-on-rewrite 是 no(默认),Redis 会继续在主线程调用 write() 写新命令到 AOF 缓冲区,同时后台线程又在拼命 fsync()——两者共用同一块磁盘队列,互相拖慢。
开了这个选项后,重写期间暂停 fsync(),只保证 write() 到内核缓冲区,性能恢复明显。但注意:这会让重写完成前最多丢失 1 秒数据(取决于上次 fsync() 时间点)。
实操建议:
- 生产环境务必设为
yes - 搭配监控:定期
redis-cli info persistence | grep -E "aof_delayed_fsync|aof_pending_bio_fsync" - 若这两个值频繁非零,优先查
iostat -x 1看%util和await
别迷信 always = 零丢失,它解决不了原子性问题
业务方常以为 appendfsync always 就能保金融级安全,其实不然:
- 单机
always仍可能丢最后几条命令(进程崩溃瞬间,fsync()已发起但未返回) - 无法防止主从切换时的命令不一致(AOF 文件写完 ≠ 从库收到并执行)
- 真正兜底要靠:应用层幂等 + 主从 WAL 同步(如 Redis 7 的 RDB-AOF 混合持久化)+ 外部双写校验
最易被忽略的一点:always 模式下,UNLINK、BGREWRITEAOF 等异步操作依然受限于主线程阻塞,该慢还是慢——它只保日志落盘,不保整体吞吐。


















