【问题标题】:fflush, fsync and sync vs memory layersfflush、fsync 和同步与内存层
【发布时间】:2015-07-23 01:41:30
【问题描述】:

我知道已经有类似的问题,我看了看,但我找不到明确的、明确的答案。我只是在网上调查这些功能及其与内存层的关系。特别是我发现了这个漂亮的article,它让我对内存层有了很好的了解

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

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

问题:

    1234563 987654336@我想]将数据同步到稳定的内存层跳过易失性?我认为这是直写式缓存发生的情况,而不是回写式缓存。根据我的阅读,我了解到fsync() 上的回写缓存可以将数据发送到将它们放入易失性缓存中的设备,并且它们只会在之后进入永久内存
  1. 我读到fsync() 使用文件描述符,然后使用单个文件,而sync() 导致缓冲区的总部署,因此它适用于要更新的​​每个数据。从这个page 也可以看出fsync() 等待写入磁盘的结束,而sync() 不等待实际写入磁盘的结束。两者之间是否存在与内存数据传输相关的其他差异?

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

【问题讨论】:

标签: c linux caching synchronization fsync


【解决方案1】:

“我没有任何解决办法,但肯定佩服这个问题。”

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

【讨论】:

    【解决方案2】:

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

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

    需要严格的写入顺序的应用程序,例如数据库 应该使用 F_FULLFSYNC 来确保他们的数据按照他们期望的顺序写入。详情请参阅 fcntl(2)。

    【讨论】:

      【解决方案3】:

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

      与此相关,我发现 同步同步 操作之间的区别在谈论该主题时非常有用。以下是Robert Love 的简洁表述:

      在写入的数据(至少)存储在内核的缓冲区缓存中之前,同步写入操作不会返回。 [...] 同步操作比单纯的同步操作更具限制性和安全性。同步写入操作将数据刷新到磁盘,确保磁盘上的数据始终与相应的内核缓冲区同步。

      考虑到这一点,您可以调用带有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 函数。这可以防止文件内容被缓存,并在每次写入时将元数据刷新到磁盘。有关详细信息,请参阅创建文件。

      显然,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. 使用您的设备驱动程序禁用磁盘缓存。
      2. 确保您使用的特定设备支持直写/无缓存策略。

      但是,如果您正在寻找数据完整性的保证,您可以只购买一个带有自己的电池供电的磁盘,该电源超越了电容器(通常仅足以完成正在进行的写入过程)。正如上面提到的博客文章中的结论:

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

      2.(部分)回答第二个问题,这是来自手册页SYNC(2)

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2011-01-21
          • 1970-01-01
          • 1970-01-01
          • 2019-06-03
          • 1970-01-01
          • 1970-01-01
          • 2014-10-24
          • 1970-01-01
          • 2013-01-06
          相关资源
          最近更新 更多