3.1.1. sync
sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。通常称为
update的系统守护进程会周期性地(一般每隔30秒)调用sync函数。这就保证了定期冲洗内核的块缓冲区。命令
sync也调用sync函数。sync会把对文件系统的元数据、缓存的文件数据写入所有底层的文件,对所有文件系统有
用。sync 和 syncfs 起作用的是文件系统缓存,这些缓存是在内核空间管理的。
3.1.2. syncfs
syncfs需要一个文件描述符,只写入文件描述符指向的文件相关的文件系统数据的数据。
3.1.3. fsync
fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘上。
3.1.4. fdatasync
fdatasync函数类似于fsync,但它只影响文件的数据部分。而除数据外,fsync还会同步更新文件的属性。对于提供事务支持的数据库,在事务提交时,都要确保事务日志(包含该事务所有的修改操作以及一个提交记录)完全写到硬盘上,才认定事务提交成功并返回给应用层。
3.2. fsync与fdatasync区别
除了同步文件的修改内容(脏页),fsync还会同步文件的描述信息(metadata,包括size、访问时间等等),因为文件的数据和metadata通常存在硬盘的不同地方,因此fsync至少需要两次IO写操作,多余的一次IO操作,根据Wikipedia的数据,当前硬盘驱动的平均寻道时间(Average seek time)大约是3~15ms,7200RPM硬盘的平均旋转延迟(Average rotational latency)大约为4ms,因此一次IO操作的耗时大约为10ms左右。Posix同样定义了fdatasync,放宽了同步的语义以提高性能:
int fdatasync(int fd);
fdatasync的功能与fsync类似,但是仅仅在必要的情况下才会同步,因此可以减少一次IO写操作。
fdatasync does not flush modified metadata unless that metadata is needed in order to allow a
subsequent data retrieval to be corretly handled.
举例来说,文件的尺寸(st_size)如果变化,是需要立即同步的,否则OS一旦崩溃,即使文件的数据部分已同步,由于metadata没有同步,依然读不到修改的内容。而最后访问时间(atime)/修改时间(mtime)是不需要每次都同步的,只要应用程序对这两个时间戳没有苛刻的要求,基本没有问题。
ref:
linux同步机制(fdatasync fsync syncfs sync)详解 - 知乎
函数sync、fsync与fdatasync的总结整理(必看篇) - 经验笔记
linux同步IO函数:sync、fsync与fdatasync - 知乎
https://lrita.github.io/images/posts/filesystem/Linux.Kernel.Write.Procedure.pdf