开发者社区> 异步社区> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

《Linux系统编程(第2版)》——2.4 同步I/O

简介: 系统调用fsync()可以确保和文件描述符fd所指向的文件相关的所有脏数据都会回写到磁盘上。文件描述符fd必须以写方式打开。该调用会回写数据和元数据,如创建的时间戳以及索引节点中的其他属性。该调用在硬件驱动器确认数据和元数据已经全部写到磁盘之前不会返回。
+关注继续查看

本节书摘来自异步社区《Linux系统编程(第2版)》一书中的第2章,第2.4节,作者:【美】Robert Love著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 同步I/O

虽然同步I/O是个很重要的主题,但不必过于担心延迟写的问题。写缓冲带来了极大的性能提升,因此,任何操作系统,甚至是那些“半吊子”的操作系统,都因支持缓冲区实现了延迟写而可以称为“现代”操作系统。然而,有时应用希望能够控制何时把数据写到磁盘。在这种场景下,Linux内核提供了一些选择,可以牺牲性能换来同步操作。

2.4.1 fsync()和fdatasync()
为了确保数据写入磁盘,最简单的方式是使用系统调用fsync(),在POSIX.1b标准中定义如下:

screenshot

系统调用fsync()可以确保和文件描述符fd所指向的文件相关的所有脏数据都会回写到磁盘上。文件描述符fd必须以写方式打开。该调用会回写数据和元数据,如创建的时间戳以及索引节点中的其他属性。该调用在硬件驱动器确认数据和元数据已经全部写到磁盘之前不会返回。

对于包含写缓存的硬盘,fsync()无法知道数据是否已经真正在物理磁盘上了。硬盘会报告说数据已经写完了,但是实际上数据还在硬盘驱动器的写缓存上。好在,在硬盘驱动器缓存中的数据会很快写入到磁盘上。

Linux还提供了系统调用fdatasync():

screenshot

fdatasync()的功能和fsync()类似,其区别在于fdatasync()只会写入数据以及以后要访问文件所需要的元数据。例如,调用fdatasync()会写文件的大小,因为以后要读该文件需要文件大小这个属性。fdatasync()不保证非基础的元数据也写到磁盘上,因此一般而言,它执行更快。对于大多数使用场景,除了最基本的事务外,不会考虑元数据如文件修改时间戳,因此fdatasync()就能够满足需求,而且执行更快。

fsync()通常会涉及至少两个I/O操作:一是回写修改的数据,二是更新索引节点的修改时间戳。因为索引节点和文件数据在磁盘上可能不是紧挨着——因而会带来代价很高的seek操作——在很多场景下,关注正确的事务顺序,但不包括那些对于以后访问文件无关紧要的元数据(比如修改时间戳),使用fdatasync()是提高性能的简单方式。
fsync()和fdatasync()这两个函数用法一样,都很简单,如下:

screenshot

而fdatasync()的使用方式如下:

screenshot

这两个函数都不保证任何已经更新的包含该文件的目录项会同步到磁盘上。这意味着如果文件链接最近刚更新,文件数据可能会成功写入磁盘,但是却没有更新到相关的目录中,导致文件不可用。为了保证对目录项的更新也都同步到磁盘上,必须对文件目录也调用fsync()进行同步。

返回值和错误码
成功时,两个调用都返回0。失败时,都返回-1,并设置errno值为以下三个值之一:

EBADF

给定文件描述符不是以写方式打开的合法描述符。

EINVAL

给定文件描述符所指向的对象不支持同步。

EIO

在同步时底层I/O出现错误。这表示真正的I/O错误,经常在发生错误处被捕获。

对于某些Linux版本,调用fsync()可能会失败,因为文件系统没有实现fsync(),即使实现了fdatasync()。某些“固执”的应用可能会在fsync()返回EINVAL时尝试使用fdatasync()。代码如下:

screenshot

在POSIX标准中,fsync()是必要的,而fdatasync()是可选的,因此在所有常见的Linux文件系统上,都应该为普通文件实现fsync()系统调用。但是,特殊的文件类型(比如那些不需要同步元数据的)或不常见的文件系统可能只实现了fdatasync()系统调用。

2.4.2 sync()
sync()系统调用用来对磁盘上的所有缓冲区进行同步,虽然它效率不高,但还是被广泛应用:

screenshot

该函数没有参数,也没有返回值。它总是成功返回,并确保所有的缓冲区——包括数据和元数据——都能够写入磁盘[4]。

POSIX标准并不要求sync()一直等待所有缓冲区都写到磁盘后才返回,只需要调用它来启动把所有缓冲区写到磁盘上即可。因此,一般建议多次调用sync(),确保所有数据都安全地写入磁盘。但是对于Linux而言,sync()一定是等到所有缓冲区都写入了才返回,因此调用一次sync()就够了。

sync()的真正用途在于同步功能的实现。应用应该使用fsync()和fdatasync()将文件描述符指定的数据同步到磁盘中。注意,当系统繁忙时,sync()操作可能需要几分钟甚至更长的时间才能完成。

2.4.3 O_SYNC标志位
系统调用open()可以使用O_SYNC标志位,表示该文件的所有I/O操作都需要同步:

screenshot

读请求总是同步操作。如果不同步,无法保证读取缓冲区中的数据的有效性。但是,正如前面所提到的,write()调用通常是非同步操作。调用返回和把数据写入磁盘没有什么关系,而标志位O_SYNC则将二者强制关联,从而保证write()调用会执行I/O同步。

O_SYNC标志位的功能可以理解成每次调用write()操作后,隐式执行fsync(),然后才返回。这就是O_SYNC的语义,虽然Linux内核在实现上做了优化。

对于写操作,O_SYNC对用户时间和内核时间(分别指用户空间和内核空间消耗的时间)有些负面影响。此外,根据写入文件的大小,O_SYNC可能会使进程消耗大量的时间在I/O等待时间,因而导致总耗时增加一两个数量级。O_SYNC带来的时间开销增长是非常可观的,因此一般只在没有其他方式下才选择同步I/O。

一般来说,应用要确保通过fsync()或fdatasync()写数据到磁盘上。和O_SYNC相比,调用fsync()和fdatasync()不会那么频繁(只在某些操作完成之后才会调用),因此其开销也更低。

2.4.4 O_DSYNC和O_RSYNC
POSIX标准为open()调用定义了另外两个同步I/O相关的标志位:O_DSYNC和O_RSYNC。在Linux上,这些标志位的定义和O_SYNC一致,其行为完全相同。

O_DSYNC标志位指定每次写操作后,只同步普通数据,不同步元数据。O_DSYNC的功能可以理解为在每次写请求后,隐式调用fdatasync()。因为O_SYNC提供了更严格的限制,把O_DSYNC替换成O_SYNC在功能上完全没有问题,只有在某些严格需求场景下才会有性能损失。

O_RSYNC标志位指定读请求和写请求之间的同步。该标志位必须和O_SYNC或O_DSYNC一起使用。正如前面所提到的,读操作总是同步的——只有当有数据返回给用户时,才会返回。O_RSYNC标志位保证读操作带来的任何影响也是同步的。也就是说,由于读操作导致的元数据更新必须在调用返回前写入磁盘。在实际应用中,可以理解成在read()调用返回前,文件访问时间必须更新到磁盘索引节点的副本中。在Linux中,O_RSYNC和O_SYNC的含义相同,虽然这没有什么意义(与O_SYNC和O_DSYNC的子集关系不同)。在Linux中,O_RSYNC无法通过当前行为来解释,最接近的理解是在每次read()调用后,再调用fdatasync()。实际上,这种行为极少发生。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Linux 同步机制比较与联系
操作系统提供的同步原语包括:互斥锁、读写锁、条件变量、信号量,支持多任务的OS一般都会实现上述几种同步方式。Linux作为多任务、多用户系统,同样实现了上述几种同步方式。对于在Linux系统下编程的程序员来说,可能都或多或少的使用或者听说过这几种方式,对于它们的基本使用方式可能都大体的解了。
25 0
linux命令之 用户和群组
一、保存用户信息的文件 1 /etc/passwd root:x:0:0:root:/root:/bin/bash pwftp:x:500:500::/alidata/www/wwwroot/:/sbin/nologin apache:x:48:48:Apache:/var/www:...
842 0
linux命令----网络地址
IP即时生效(重启后失效): ifconfig eth0 192.168.1.102 netmask 255.255.255.0  route add default gw 192.168.
734 0
linux命令(不常见但好用,个人总结)
<h3><span style="font-family:SimSun; font-size:14px">1、删除命令</span></h3> <p></p> <pre name="code" class="cpp">rm -r xxxx 递归删除 rm -rf xxxx 删除整个文件夹</pre> <br><h3><span style="font-family:
1285 0
Sed 与 Linux 等价命令代码鉴赏(转)
参考了     http://www.chinaunix.net/jh/24/307045.html                       sed     http://bbs.chinaunix.net/viewthread.php?tid=316482                 awk 这两篇文章,感觉关于Sed还有东西可以写.顺便考察考察自己的Sed水平.                                          增加了中没有的命令, 对其中大部 分原有命令做了修改。
841 0
Linux下的tree命令 --Linux下目录树查看
Linux下的tree命令 --Linux下目录树查看   有时我们需要生成目录树结构,可以使用的有ls -R,但是实际效果并不好   这时需要用到tree命令,但是大部分Linux系统...
641 0
Linux禁止非WHEEL用户使用SU命令
        通常情况下,一般用户通过执行“su -”命令、输入正确的root密码,可以登录为root用户来对系统进行管理员级别的配置。        但是,为了更进一步加强系统的安全性,有必要建立一个管理员的 组,只允许这个组的用户来执行“su -”命令登录为root用户,而让其他组的用户即使执行“su -”、输入了正确的root密码,也无法登录为root用户。
942 0
Linux用户管理命令(第二版)
添加用户 1、useradd -设置选项 用户名 【-D 查看缺省参数 】 选项: u: UID 【必须是系统中没有的】 g:缺省所属用户组GID[最好有] G: 指定用户所属多个...
669 0
Linux文件系统管理命令(第二版)
Linux文件系统管理命令 常用命令 1、df命令 查看分区使用情况 常用选项 -h 比较人性化 -m 以兆字节显示分区使用情况 显示信息: Mounted on:挂载点 Files...
917 0
+关注
异步社区
异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。
12049
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载