配置了appendfsync everysec并不等于崩溃后最多丢1秒数据,因主线程阻塞、page cache延迟、硬件写缓存、no-appendfsync-on-rewrite错配等因素,实际可能丢失数秒至全部缓冲区数据。

配置了 appendfsync everysec 并不等于“崩溃后最多丢 1 秒数据”——真实场景中,它可能丢几秒、几十秒,甚至全部缓冲区内容。这不是 Redis 故意违约,而是它无法绕过操作系统、硬件和自身线程模型的物理限制。
everysec 的 fsync 不是由内核定时器保障的
Redis 的 everysec 依赖主线程里的一个定时任务(类似 event loop 中的周期检查),不是靠 timerfd 或 POSIX timer 等内核级机制驱动。一旦主线程被阻塞,这个定时器就停摆:
-
KEYS *、FLUSHALL、大 value 序列化(如GET几百 MB 的 string)会卡住主线程数百毫秒,导致 fsync 被跳过 - Lua 脚本里密集调用
redis.call()或含长循环时,事件循环完全冻结,fsync 定时器不会触发 - 后台
bgrewriteaof运行期间若磁盘 I/O 延迟飙升(如 SSD GC、RAID 卡电池学习),Redis 可能临时降级为no-appendfsync-on-rewrite yes行为,积压的 AOF 缓冲区仍滞留内存
page cache 和磁盘写缓存让 fsync() 返回 ≠ 数据落盘
fsync() 系统调用返回成功,只表示数据已从用户空间进入内核 page cache,并通知设备“准备刷写”,不代表已写入闪存或磁盘扇区:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- ext4 文件系统若挂载时带
barrier=0,内核可能重排 write + fsync 顺序,fsync()返回后数据仍在 page cache 中 - SSD/机械盘默认开启 Write Cache(用
hdparm -I /dev/sdX | grep "Write cache"查,输出含enabled就危险),需手动执行hdparm -W0 /dev/sdX关闭 - 即使关了硬件缓存,若系统在
write()后、fsync()前被SIGKILL或 OOM Killer 杀死,那条命令就永远卡在用户态缓冲区里,never reach disk
no-appendfsync-on-rewrite 配置错配会放大 everysec 风险
这个配置常被忽略,但它和 everysec 是隐式强耦合关系:
- 默认值是
no-appendfsync-on-rewrite no:重写期间仍坚持每秒 fsync,看似安全,但若此时磁盘延迟高,Redis 会记录Asynchronous AOF fsync is taking too long日志,且后续 fsync 可能进一步延迟 - 若误设为
yes,重写期间直接跳过所有 fsync,AOF 缓冲区可能积压数秒命令——这比everysec本身更危险 - 验证方式:运行
redis-cli config get no-appendfsync-on-rewrite,必须与你的磁盘能力匹配,不能仅看文档默认值
真正决定 everysec 实际效果的,从来不是配置文件里那一行,而是 iostat -x 1 里的 await、perf trace 抓到的 sys_enter_fsync 间隔、以及 hdparm 检查出的硬件缓存状态。线上环境不测真实 fsync 行为,只改配置,等于在盲区开车。

















