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

appendfsync always 为什么让 Redis 主线程卡死
因为每次写命令(SET、INCR、LPUSH等)执行完,Redis 主线程必须调用 fsync() 等待磁盘硬件返回“已落盘”信号才返回响应。这不是发个指令就完的事——它是同步阻塞系统调用,主线程全程挂起。
常见错误现象:redis-cli --latency 显示 P99 延迟跳到 20–50ms;日志反复刷出 Asynchronous AOF fsync is taking too long;INFO persistence 里 aof_delayed_fsync 每秒涨几十甚至上百。
- SSD 单次
fsync()平均耗时 0.2–1ms,但高并发下请求排队,延迟叠加严重 - 即使挂 NVMe,若文件系统是 ext4 且未启用
data=writeback,fsync()还得等 journal 落盘 -
top里 CPU 占用可能很低,但 I/O 已满负荷——别只盯着 CPU 看
怎么确认是不是被 always 拖垮了
别猜,直接查两个关键指标和磁盘状态:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 运行
redis-cli info persistence | grep -E "aof_delayed_fsync|aof_pending_bio_fsync":只要任一非零,说明刷盘已滞后 - 跑
iostat -x 1:看%util是否长期 >80%,await是否 >10ms,w/s是否卡在磁盘 IOPS 极限(SATA SSD ≈3000,机械盘 ≈150) - 跑
iotop -o -a过滤redis-server:如果WRITE列稳定在几百 KB/s,就是被fsync()反复掐住脖子的典型特征
everysec 和 always 的真实性能差在哪
根本区别是 I/O 耦合程度:everysec 把主线程和磁盘解耦了,always 把所有写请求焊死在同一根 I/O 绳子上。
-
everysec:主线程只做write()到内核缓冲区(微秒级),后台线程每秒统一fsync()一次——相当于把 10 万次小写合并成约 1000 次大写,IOPS 压力骤降一个数量级 -
always:实测 10K QPS 写入下,吞吐常跌到不足 2K,本质是被磁盘随机写 IOPS 卡死 - 云盘标称 IOPS 是理论峰值,实际受 IO 调度器、队列深度影响,往往只有 6–8 折;用
fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=4k --size=1G --runtime=60单独压测才能拿到真实基准
no-appendfsync-on-rewrite yes 不是可选项,是保命配置
AOF 重写(bgrewriteaof)期间,若 no-appendfsync-on-rewrite 是 no(默认),主线程继续 fsync(),子进程拼命读磁盘,两者抢同一块 I/O 队列,结果是主线程 write() 被阻塞、QPS 瞬间归零。
- 设为
yes后,重写期间暂停fsync(),只保证write()到内核缓冲区,性能恢复明显 - 代价是重写窗口期最多丢失 1 秒数据(与
everysec一致),但避免了雪崩式 QPS 断崖 - 这个配置不开启,
appendfsync always或everysec都可能在重写时突然崩掉
真正容易被忽略的点是:即使你写了 appendfsync everysec,如果磁盘本身延迟突增,Redis 会自动降级为 always 刷盘——这个行为由 no-appendfsync-on-rewrite 控制,但文档里几乎不提,线上故障时极难定位。

















