直接回答:路径:应用缓冲区 → write() 拷贝到内核 page cache(此时即返回,这就是“写已落盘”的错觉来源)→ 后台 flusher 线程按脏页比例/超时策略回写 → 块层调度(mq-deadline/none)→ 驱动 → 磁盘控制器缓存 → 介质。fsync 做的是强制把该文件的脏页推过整条链并等设备确认,慢在三处:磁盘寻道/旋转延迟(HDD 毫秒级)、控制器缓存刷入、以及它要等整条 IO 路径排空——SSD 上 fsync 也要几十到几百微秒。

展开解析:工程含义:数据库与消息队列的持久性承诺全靠 fsync 语义(WAL 写完 + fsync 才应答),所以它们对 fsync 延迟极其敏感——MySQL 的 innodb_flush_log_at_trx_commit=1 意味着每事务一次 fsync,这是 TPS 的硬上限,改成 2(每秒刷)拿性能换最多丢一秒数据。常见认知错误:write 返回成功不等于落盘(掉电丢 page cache 里的脏数据);close 不保证刷盘;O_DIRECT 绕过 page cache 自己管缓冲(数据库常用,避免双缓冲)。观测:/proc/meminfo 的 Dirty/Writeback、iostat 的 await、pidstat -d;写放大问题——page cache 的脏页合并本来能减少 IO,过激进的回写参数(dirty_ratio 太小)会制造大量小 IO。挂载选项也有戏:noatime 消除读操作引发的元数据写,data=writeback(ext4)用元数据日志换数据完整性窗口。分布式系统里还要注意:fsync 成功只在单机语义内成立,跨机持久性要靠复制协议。

追问方向:fdatasync 与 fsync 差别?group commit 如何摊薄 fsync 成本?

(约 490 字)