大家好,又见面了,我是你们的朋友全栈君。
在Linux系统中,对文件系统上文件的读写一般是通过页缓存(page cache)进行的(DirectIO除外),这样设计的可以延时磁盘IO的操作,从而可以减少磁盘读写的次数,提升IO性能。但是性能和可靠性在一定程度上往往是矛盾的,虽然内核中设计有一个工作队列执行赃页回写同磁盘文件进行同步,但是在一些极端的情况下还是免不了掉电数据丢失。因此内核提供了sync、fsync、fdatasync和msync系统调用用于同步,其中sync会同步整个系统下的所有文件系统以及块设备,而fsync和fdatasync只针对单独的文件进行同步,msync用于同步经过mmap的文件。使用这些系统API,用户可以在写完一些重要文件之后,立即执行将新写入的数据回写到磁盘,尽可能的降低数据丢失的概率。本文将介绍fsync和fdatasync的功能和区别,并以Ext4文件系统为例,分析它们是如何将数据同步到磁盘中的。
内核版本:Linux 4.10.1
内核文件:fs/sync.c、fs/ext4/fsync.c、fs/ext4/inode.c、mm/filemap.c
1、概述
当用户在写一个文件时,若在open时没有设置O_SYNC和O_DIRECT,那么新write的数据内容将会暂时保存在页缓存(page cache)中,对应的页成为赃页(dirty page),这些数据并不会立即写回磁盘中。同时内核中设计有一个等待队列bdi_wq以及一些writeback worker,它们在达到一定的条件之后(延迟时间到期(默认5s)、系统内存不足、赃页超过阈值等)就会被唤醒执行赃页(dirty page)的回写操作,文件中新写入的数据在此时才能够写回磁盘。虽然从write操作到writeback之间的窗口时间(Ext4默认启用delay
alloc特性,该时间延长到了30s)较短,若在此期间设备掉电或者系统奔溃,那用户的数据将会丢失。因此,对于单个文件来说,如果需要提高可靠性,可以在写入后调用fsync和fdatasync来实现文件(数据)的同步。
fsync系统调用会同步fd表示文件的所有数据,包括数据和元数据,它会一直阻塞等待直到回写结束。fdatasync同fsync类似,但是它不会回写被修改的元数据,除非对于一些对于数据完整性检索有关的场景。例如,若仅是文件的最后一次访问时间(st_atime)或最后一次修改时间(st_mtime)发生变化是不需要同步元数据的,因为它不会影响文件数据块的检索,若是文件的大小改变了(st_isize)则显然是需要同步元数据的,若不同步则可能导致系统崩溃后无法检索修改的数据。鉴于fdatasync的以上区别,可以看出应用程序对一些无需回写文件元数据的场景使用fdatasync可以提升性能。
需要注意,如果物理磁盘的write cache被使能,那么fsync和fdatasync将不能保证回写的数据被完整的写入到磁盘存储介质中(数据可能依然保存在磁盘的cache中没有写入介质),因此可能会出现明明调用了fsync系统调用但是数据在掉电后依然丢失了或者出现文件系统不一致的情况。
最后,关于fsync和fdatasync的详细描述可以参考fsync的manual page。
————————————————
版权声明:本文为CSDN博主「luckyapple1028」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/luckyapple1028/article/details/61413724
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/139547.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...