我知道已经有类似的问题了,我看了一下,但我找不到一个明确的答案。我只是在网上调查了这些功能及其与内存层的关系。特别是我发现了这个漂亮的article,它让我对内存层有了很好的了解
看起来fflush()
将数据从应用程序移动到内核文件系统缓冲区,这是可以的,每个人似乎都同意这一点。唯一让我感到困惑的是,在同一篇文章中,他们假设了一个回写缓存,说使用fsync()
“数据被保存到稳定存储层”,然后他们补充说“存储可以自己将数据存储在回写缓存中,因此,使用O_DIRECT打开的文件仍需要fsync()
,以便将数据保存到稳定存储”
阅读here和there,看起来事实是fsync()
和sync()
让数据进入存储设备,但如果此设备具有缓存层,则它只是移动到此处,除非我们有一个启用了屏障的文件系统,然后“sync()
/fsync()
和一些其他操作将导致相应的“缓存刷新”(ATA)或“同步缓存”(SCSI)命令发送到设备”[来自您的网站answer]
问题:
1.如果要更新的数据已经在内核缓冲区中,并且我的设备有一个处于回写模式的易失性缓存层,那么像fsync()
[我想还有sync()
]这样的操作是否会跳过易失性缓存层将数据同步到稳定的内存层?我认为这就是直写缓存的情况,从我所读到的内容中,我了解到fsync()
上的回写缓存可以将数据发送到设备,设备将数据放入易失性缓存中,只有在
1.我读到fsync()
处理文件描述符,然后处理单个文件,而sync()
导致缓冲区的总部署,因此它适用于要更新的每一个数据。从这个page还可以看出,fsync()
等待写入磁盘的结束,而sync()
不等待实际写入磁盘的结束。两者之间的内存数据传输是否存在其他差异?
感谢那些愿意帮助我们的人
4条答案
按热度按时间axr492tv1#
**1.**正如您从研究中得出的正确结论,
fflush
将 * 用户空间缓冲 * 数据同步到 * 内核级 * 缓存(因为它使用的是FILE
对象,这些对象驻留在用户级,对内核不可见),而fsync
或sync
(直接使用 * 文件描述符 *)将内核缓存数据与设备同步。但是,后者并不保证数据实际上已经被写入存储设备-因为这些存储设备通常也具有它们自己的高速缓存。我希望对使用MS_SYNC
标志调用的msync
也执行相同的保持操作。与此相关的是,我发现 synchronized 和 synchronous 操作之间的区别在讨论这个主题时非常有用。
[......]同步写操作比单纯的同步操作限制更严格,也更安全。同步写操作将数据刷新到磁盘,确保磁盘上的数据始终与相应的内核缓冲区保持同步。
考虑到这一点,你可以使用
O_SYNC
标志(以及其他一些以写权限打开文件的标志)调用open
来强制执行同步写操作。同样,正如你正确地假设的那样,这只适用于WRITE THROUGH
磁盘缓存策略,这实际上相当于 * 禁用 * 磁盘缓存。您可以阅读this answer了解如何在Linux上禁用磁盘缓存。请务必查看this website,它还包括基于SCSI和基于ATA的设备(要了解不同类型的磁盘,请参阅此page on Microsoft SQL Server 2005,最后更新:2018年4月19日)。
说到这里,阅读有关如何在Windows machines上处理此问题的信息非常有用:
若要开启未缓冲I/O的档案,请使用FILE_FLAG_NO_BUFFERING和FILE_FLAG_WRITE_THROUGH旗标呼叫CreateFile函数。这会防止快取档案内容,并在每次写入时将描述数据清除至磁盘。如需详细信息,请参阅CreateFile。
显然,Microsoft SQL Server 2005系列就是这样确保数据完整性的:
所有版本得SQL Server都使用Win32 CreateFile函数打开日志与数据文件. dwFlagsAndAttributes成员在由SQL Server打开时包括FILE_FLAG_WRITE_THROUGH选项. [...]此选项指示系统通过任何中间缓存写入并直接转到磁盘.系统仍然可以缓存写操作,但不能延迟刷新它们.
我说这是信息性的,特别是因为这个blog post from 2012显示一些SATA磁盘 * 忽略 *
FILE_FLAG_WRITE_THROUGH
!我不知道当前的情况是什么,但似乎为了确保写入磁盘是真正同步的,您需要:1.使用设备驱动程序禁用磁盘缓存。
1.确保您使用的特定设备支持直写/无缓存策略。
然而,如果您正在寻找数据完整性的保证,您可以购买一个自带电池供电的磁盘,其供电能力超过了电容器(通常只够完成正在进行的写入过程)。
底线是,使用企业级磁盘来存储数据和事务日志文件。[...]实际上,情况并不像看起来那么戏剧化。许多RAID控制器都有电池支持的缓存,不需要荣誉直写要求。
**2.**为了(部分地)回答第二个问题,以下内容摘自手册页
SYNC(2)
:根据标准规范(例如POSIX. 1 -2001),sync()调度写操作,但可能在实际写操作完成之前返回。然而,由于版本1. 3. 20,Linux实际上会等待。(这仍然不能保证数据完整性:现代磁盘具有大的缓存。)
这意味着
fsync
和sync
的工作方式不同,但是,请注意,它们都是在unistd.h
中实现的,这表明它们之间存在一定的一致性。但是,我会跟随Robert Love,他不建议在编写自己的代码时使用sync
系统调用。sync()的唯一真实的用途是在同步实用程序的实现中。应用程序应该使用fsync()和fdatasync()来只将必需的文件描述符的数据提交到磁盘。请注意,sync()在忙碌的系统中可能需要几分钟或更长时间才能完成。
7kjnsjlb2#
“我没有任何解决办法,但肯定很欣赏这个问题。”
我从你的优秀参考资料中读到的是,没有标准。标准在内核中的某个地方结束。内核控制设备驱动程序和设备驱动程序(可能由磁盘制造商提供)通过API控制磁盘制造商可能已经添加了电容器/电池,其具有刚好足够的功率以在电源故障的情况下刷新其设备缓冲器,或者他可能没有。设备可能提供同步功能,但这是否真正同步(刷新)设备缓冲区尚不清楚(取决于设备)。因此,除非您根据您的规格选择并安装设备(并验证这些规格),否则您永远无法确定。
dhxwm5r43#
这是一个公平的问题。即使在处理了错误条件之后,你也不能保证数据在你的存储中的安全。
fsync的手册页清楚地解释了这个问题!!:)对于需要更严格地保证数据完整性的应用程序,Mac OS X提供了F_FULLFSYNC fcntl。F_FULLFSYNC fcntl要求驱动器将所有缓冲数据刷新到永久存储。
要求严格写入顺序的应用程序(如数据库)应使用F_FULLFSYNC来确保其数据按预期顺序写入。有关详细信息,请参阅fcntl(2)。
watbbzwu4#
是的,弗鲁什()确保数据离开进程内存空间,但它可能在RAM的脏页中等待写回。这可以防止应用程序中止,但不能防止系统崩溃或电源故障。即使电源已备份,系统也可能由于某些软件漏洞而崩溃!正如其他答案/评论中提到的,从以磁性方式写入磁盘的脏页或SSD所做的任何事情中获取数据,不是停留在磁盘控制器或驱动器中的某个易失性缓冲区中,而是正确的调用或打开选项以及正确的控制器和设备的组合!调用给予您能够更好地控制开销,在事务结束时写入更多的内容。
例如,RDBMS不仅需要担心数据库保存的文件,还需要担心日志文件,以便在磁盘丢失后以及崩溃后重新启动RDBMS时进行恢复。事实上,为了保持速度,日志中的一些文件可能比数据库中的文件更同步,因为恢复不是一个频繁的过程,通常也不是一个很长的过程。