14

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

记忆层

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

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

问题:

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

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

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

4

4 回答 4

2

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

相关地,我发现在谈论该主题时,同步操作和同步操作之间区别非常有用。以下是罗伯特·洛夫的简洁表述:

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

考虑到这一点,您可以调用openwith O_SYNCflag(连同其他一些使用写权限打开文件的标志)来强制执行同步写操作。同样,正如您正确假设的那样,这仅适用于WRITE THROUGH磁盘缓存策略,这实际上相当于禁用磁盘缓存。

您可以阅读有关如何在 Linux 上禁用磁盘缓存的答案。请务必查看该网站,该网站除了基于 ATA 的设备外,还涵盖了基于 SCSI 的设备(要了解不同类型的磁盘,请参阅Microsoft SQL Server 2005 上的此页面,最后更新时间:2018 年 4 月 19 日)。

说到这一点,阅读有关如何在Windows 机器上处理该问题的信息非常有用:

要为无缓冲 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 选项。[...]此选项指示系统通过任何中间缓存写入并直接进入磁盘。系统仍然可以缓存写操作,但不能延迟刷新它们。

我说这特别有用,因为2012 年的这篇博客文章显示一些 SATA 磁盘忽略FILE_FLAG_WRITE_THROUGH! 我不知道目前的情况如何,但似乎为了确保写入磁盘是真正同步的,您需要:

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

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

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

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

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

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

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

于 2019-10-01T09:28:32.790 回答
0

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

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

于 2015-05-12T10:15:25.833 回答
0

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

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

需要严格的写入顺序的应用程序(例如数据库)应使用 F_FULLFSYNC 以确保其数据按预期顺序写入。有关详细信息,请参阅 fcntl(2)。

于 2018-06-19T07:20:31.823 回答
0

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

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

于 2020-07-02T20:54:17.917 回答