fflush,fsync和sync与内存层

时间:2015-05-12 09:14:16

标签: c linux caching sync fsync

我知道已经有类似的问题了,我给了他们一看,但我找不到明确的单一答案来回答我的问题。我只是在网上调查这些函数及其与内存层的关系。特别是我发现这个漂亮的article让我对记忆层有了很好的了解。

memory layers

似乎fflush()将数据从应用程序移动到内核文件系统缓冲区,没关系,每个人似乎都同意这一点。让我感到困惑的唯一一件事是,在同一篇文章中,他们假设一个回写缓存,说fsync()“数据被保存到稳定存储层”,并且在他们添加“存储本身可以存储”之后回写缓存中的数据,因此使用O_DIRECT打开的文件仍然需要fsync()以便将数据保存到稳定存储“

阅读herethere似乎事实是fsync()sync()让数据进入存储设备,但如果这个数据有缓存层,那么它就是搬到这里,不是立即永久存储,如果出现电源故障,数据甚至可能会丢失。除非我们有一个启用了障碍的文件系统,然后“sync() / fsync()和其他一些操作将导致相应的CACHE FLUSH(ATA)或SYNCHRONIZE CACHE(SCSI)命令被发送到设备”[来自您的网站answer]

问题:

  1. 如果要更新的数据已经在内核缓冲区中并且我的设备在回写模式下有一个易失性缓存层,那么就像文章所说的那样,fsync()之类的操作是真的和sync()我想将数据同步到稳定的内存层,跳过易失性的数据?我认为这是通过直写缓存而不是回写缓存所发生的情况。根据我的阅读,我了解到fsync()上的回写缓存只能将数据发送到设备,将数据放入易失性缓存中,只有在

  2. 我读到fsync()使用文件描述符然后使用单个文件,而sync()导致缓冲区的完全部署,因此它适用于每个要更新的数据。从这个page开始,fsync()等待写入磁盘的结束,而sync()不等待实际写入磁盘的结束。两者之间的内存数据传输是否存在其他差异?

  3. 感谢那些愿意提供帮助的人

4 个答案:

答案 0 :(得分:0)

"我没有任何解决方案,但肯定很佩服这个问题。"

从我从你的好参考中读到的一切,是没有标准。标准在内核中的某个地方结束。内核控制设备驱动程序,设备驱动程序(可能由磁盘制造商提供)通过API控制磁盘(设备上有小型计算机)。制造商可能添加了足够功率的电容器/电池,以便在电源故障时冲洗其设备缓冲器,或者他可能没有。设备可以提供同步功能,但是否真正同步(刷新)设备缓冲区是未知的(取决于设备)。因此,除非您根据您的规格选择并安装设备(并验证这些规格),否则您永远不会确定。

答案 1 :(得分:0)

这是一个公平的问题。即使在处理错误情况之后,您也无法确保存储中的数据存在。

fsync的手册页清楚地解释了这个问题! :) 适用于需要更严格保证完整性的应用 他们的数据,Mac OS X提供F_FULLFSYNC fcntl。 F_FULLFSYNC fcntl要求驱动器将所有缓冲的数据刷新到永久存储器。

需要严格排序的应用程序(如数据库) 应该使用F_FULLFSYNC来确保他们的数据按照他们期望的顺序写入。有关更多详细信息,请参阅fcntl(2)。

答案 2 :(得分:0)

1。。正如您从研究中正确得出的结论,fflush用户空间缓冲的数据同步到内核级缓存(因为它与驻留在用户级别且对内核不可见的FILE对象一起工作),而fsyncsync(直接与文件描述符一起工作)将内核缓存的数据与设备同步。但是,后者并不能保证数据已实际写入存储设备中,因为这些数据通常也带有自己的缓存。我希望msync标志也MS_SYNC具有相同的保有量。

相关地,在讨论该主题时,我发现 synchronized synchronous 操作之间的区别非常有用。 Robert Love简洁地说:

  

直到写入的数据至少存储在内核的缓冲区高速缓存中,同步写入操作才会返回。同步操作比仅同步操作更具限制性和安全性。同步的写操作会将数据刷新到磁盘,以确保磁盘上的数据始终与相应的内核缓冲区保持同步。

请牢记,您可以使用带有open标志的O_SYNC(连同其他一些具有写许可权的打开文件的标志)来强制执行同步的写操作。再次,正如您正确地假设的那样,这仅适用于WRITE THROUGH磁盘缓存策略,该策略实际上等于禁用磁盘缓存。

您可以阅读this answer,了解如何在Linux上禁用磁盘缓存。确保还检查this website,该文件除涵盖基于ATA的设备外,还涵盖基于SCSI的内容(要了解不同类型的磁盘,请参见此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函数打开日志和数据文件。当由SQL Server打开时,dwFlagsAndAttributes成员包括FILE_FLAG_WRITE_THROUGH选项。 [...]   此选项指示系统写入所有中间高速缓存并直接进入磁盘。系统仍然可以缓存写操作,但是不能延迟刷新它们。

我之所以说这特别有用,是因为blog post from 2012表明某些SATA磁盘忽略 FILE_FLAG_WRITE_THROUGH!我不知道当前的状态是什么,但是为了确保真正同步写入磁盘,您需要:

  1. 使用设备驱动程序禁用磁盘缓存。
  2. 请确保您使用的特定设备支持直写/无缓存策略。

但是,如果您要确保数据完整性,则可以购买具有其自身基于电池的电源的磁盘,该电源超出了电容器的容量(通常仅足以完成正在进行的写入过程)。如上述博客文章中的结论所述:

  

最重要的是,使用企业级磁盘存储数据和事务日志文件。 [...]实际上,情况并不像看起来那样严重。许多RAID控制器具有备用电池缓存,不需要满足直写要求。

2。。要(部分)回答第二个问题,该问题来自手册页SYNC(2)

  

根据标准规范(例如POSIX.1-2001),sync()计划写入,但可能在完成实际写入之前返回。但是,由于1.3.20版Linux实际上确实在等待。 (这仍然不能保证数据的完整性:现代磁盘具有较大的缓存。)

这意味着fsyncsync的工作方式不同,但是请注意,它们都在unistd.h中实现,这表明它们之间存在一定的一致性。但是,我会遵循Robert Love,他在编写自己的代码时不建议使用sync syscall。

  

sync()的唯一真正用途是在同步实用程序的实现中。应用程序应使用fsync()和fdatasync()来提交仅必需文件描述符的数据到磁盘。请注意,在繁忙的系统上,sync()可能需要几分钟或更长时间才能完成。

答案 3 :(得分:0)

是的,fflush()确保数据离开进程内存空间,但是它可能在RAM的脏页中等待写回。这可以防止应用程序中止,但不能防止系统崩溃或电源故障。即使备份电源,系统也可能由于某些软件漏洞而崩溃!如其他答案/评论中所述,将磁页或任何SSD脏页中的数据以磁性方式写入磁盘,而不是将其卡在磁盘控制器或驱动器的某些易失性缓冲区中,是正确的调用或打开选项以及正确的控制器的组合和设备!调用使您可以更好地控制开销,并在事务结束时批量写入更多内容。

例如,

RDBMS不仅需要担心数据库保存文件,而且还要更加担心允许恢复的日志文件,无论是磁盘丢失之后还是崩溃后重新启动的任何RDBMS上。实际上,为了保持速度,日志中的某些日志可能比数据库中的日志更加同步,因为恢复不是一个频繁的过程,通常也不是一个漫长的过程。如果日志是完整的,则可以保证事务写入日志的内容是可恢复的。