Linux中的文件编辑是否直接保存到磁盘中?

Linux中的文件编辑是否直接保存到磁盘中?

我曾经认为文件更改会直接保存到磁盘中,也就是说,一旦我关闭文件并决定单击/选择保存。然而,在最近的一次谈话中,我的一位朋友告诉我,这通常不是真的。操作系统(特别是我们谈论的是 Linux 系统)将更改保存在内存中,并且它有一个守护进程,实际上将内存中的内容写入磁盘。

他甚至举了外部闪存驱动器的例子:这些驱动器被安装到系统中(复制到内存中),有时会发生数据丢失,因为守护进程尚未将内容保存到闪存中;这就是我们卸载闪存驱动器的原因。

我对操作系统的功能一无所知,因此我完全不知道这是否属实以及在什么情况下发生。我的主要问题是:这种情况是否会像 Linux/Unix 系统(也许还有其他操作系统)中描述的那样发生?例如,这是否意味着如果我关闭计算机立即地编辑并保存文件后,我的更改很可能会丢失?也许这取决于磁盘类型——传统硬盘与固态磁盘?

这个问题特别指的是具有磁盘来存储信息的文件系统,尽管任何澄清或比较都受到了好评。

答案1

如果我编辑并保存文件后立即关闭计算机,我的更改很可能会丢失吗?

他们可能是。我不会说“最有可能”,但可能性取决于很多因素。


提高文件写入性能的一个简单方法是操作系统仅缓存数据,告诉(欺骗)应用程序写入过程,然后稍后实际执行写入。如果同时发生其他磁盘活动,这尤其有用:操作系统可以优先考虑读取并稍后进行写入。它还可以完全消除实际写入的需要,例如,在随后快速删除临时文件的情况下。

如果存储速度慢,缓存问题会更加明显。将文件从快速 SSD 复制到慢速 USB 记忆棒可能会涉及大量写入缓存,因为 USB 记忆棒无法跟上。但您的cp命令返回速度更快,因此您可以继续工作,甚至可能编辑刚刚复制的文件。


当然,像这样的缓存有您注意到的缺点,一些数据可能在实际保存之前丢失。如果编辑器告诉他们写入成功,但文件实际上并不在磁盘上,用户会很生气。这就是为什么有fsync()系统调用,它应该仅在文件实际到达磁盘后返回。您的编辑器可以使用它来确保数据正常,然后再向用户报告写入成功。

我说“应该”,因为驱动器本身可能会对操作系统说同样的谎言,并说写入已完成,而文件实际上只存在于驱动器内的易失性写入缓存中。根据驱动器的不同,可能没有办法解决这个问题。

除了 之外fsync(),还有sync()syncfs()系统调用,要求系统确保所有系统范围的写入或特定文件系统上的所有写入都已命中磁盘。该实用程序sync可用于调用它们。

然后还有O_DIRECT标记为open(),它应该“尝试最小化进出该文件的 I/O 的缓存影响”。删除缓存会降低性能,因此它主要由自己进行缓存并希望控制它的应用程序(数据库)使用。 (O_DIRECT并非没有问题,手册页中关于它的评论有点有趣。)


断电时发生的情况也取决于文件系统。您应该关心的不仅仅是文件数据,还有文件系统元数据。如果找不到文件数据,那么将文件数据保存在磁盘上也没有多大用处。仅仅将文件扩展到更大的大小就需要分配新的数据块,并且需要在某处标记它们。

文件系统如何处理元数据更改以及元数据和数据写入之间的顺序差异很大。例如ext4,如果您设置了 mount 标志data=journal,那么所有写入(甚至数据写入)都会通过日志,并且应该相当安全。这也意味着它们被写入两次,因此性能会下降。默认选项尝试对写入进行排序,以便在更新元数据之前数据位于磁盘上。其他选项或其他文件系统可能更好或更差;我什至不会尝试进行全面的研究。


实际上,在负载较轻的系统上,文件应在几秒钟内到达磁盘。如果您正在处理可移动存储,请在拉出介质之前卸载文件系统,以确保数据实际发送到驱动器,并且没有进一步的活动。 (或者让你的 GUI 环境为你做这件事。)

答案2

有一个极其简单的方法来证明它不能确实,文件编辑总是直接保存到磁盘,即存在以下文件系统:一开始就没有磁盘支持。如果文件系统没有首先是一个磁盘,然后是不可能将更改写入磁盘,曾经

一些例子是:

  • tmpfs,仅存在于 RAM 中(或更准确地说,存在于缓冲区高速缓存中)的文件系统
  • ramfs,仅存在于RAM中的文件系统
  • 任何网络文件系统(NFS、CIFS/SMB、AFS、AFP...)
  • 任何虚拟文件系统 ( sysfs, procfs, devfs, shmfs, ...)

但即使对于磁盘支持的文件系统,情况通常也不是这样。这一页如何损坏 SQLite 数据库有一个章节叫做同步失败其中描述了写入(在本例中提交到 SQLite 数据库)可能无法到达磁盘的多种不同方式。 SQLite 还有一份白皮书解释了您必须跳过的许多环节才能保证SQLite 中的原子提交。 (注意原子写比问题更难,但是当然写入磁盘是原子写入的子问题,您也可以从本文中了解有关该问题的很多信息。)本文有一节介绍可能出错的事情其中包括关于不完整的磁盘刷新给出了一些可能阻止写入到达磁盘的微妙复杂性的示例(例如 HDD 控制器报告它已写入磁盘,但实际上尚未写入磁盘 – 是的,有些 HDD 制造商这样做,并且可能会这样做)甚至根据 ATA 规范也是合法的,因为它在这方面的措辞含糊不清)。

答案3

确实,大多数操作系统(包括 Unix、Linux 和 Windows)都使用写入缓存来加速操作。这意味着在不关闭计算机的情况下关闭计算机是一个坏主意,可能会导致数据丢失。如果您在准备移除 USB 存储设备之前将其移除,也会出现同样的情况。

大多数系统还提供同步写入的选项。这意味着在应用程序收到成功确认之前数据将存储在磁盘上,但代价是速度会变慢。

简而言之,您应该正确关闭计算机并正确准备 USB 存储以供移除,这是有原因的。

答案4

在负载较轻的系统上,内核会让新写入的文件数据在页面缓存中保留大约 30 秒write(),然后将其刷新到磁盘,以针对很快再次删除或修改的情况进行优化。

Linux 的dirty_expire_centisecs默认值为 3000(30 秒),并控制新写入的数据“过期”之前的时间。 (看https://lwn.net/Articles/322823/)。

https://www.kernel.org/doc/Documentation/sysctl/vm.txt有关更多相关的可调参数,请通过 google 获取更多信息。 (例如谷歌上dirty_writeback_centisecs)。

Linux 默认值为/proc/sys/vm/dirty_writeback_centisecs500(5 秒),PowerTop 建议将其设置为 1500(15 秒)以降低功耗。


延迟写回还可以让内核有时间在开始将文件写入磁盘之前查看文件有多大。具有延迟分配的文件系统(例如 XFS,可能还有现在的其他文件系统)甚至不会在必要时选择在磁盘上放置新写入文件的数据的位置,而不是为 inode 本身分配空间。例如,这可以让他们避免将大文件的开头放在其他文件之间 1 兆的间隙中,从而减少碎片。

如果正在写入大量数据,则可以通过页面缓存中可以有多少脏数据(尚未同步到磁盘)的阈值来触发写回磁盘。

不过,如果您没有做太多其他事情,则在小文件上单击“保存”后,您的硬盘驱动器活动指示灯将不会亮起 5(或 15)秒。


如果你的编辑器fsync()在写入文件后使用,内核将立即将其写入磁盘。 (并且fsync在数据实际发送到磁盘之前不会返回)。


写缓存之内磁盘也可以是一个东西,但磁盘通常会尝试尽快将其写入缓存提交到永久存储,这与 Linux 的页面缓存算法不同。磁盘写入缓存更像是一个存储缓冲区,用于吸收小突发写入,但也可能延迟写入以利于读取,并为磁盘固件空间提供优化查找模式的空间(例如,进行两次附近的写入或读取,而不是进行一次) ,然后远寻,再回寻。)

在旋转(磁性)磁盘上,如果在写入之前存在挂起的读/写操作,则在来自 SATA 写入命令的数据实际上不会断电之前,您可能会看到一些每次 7 到 10 毫秒的寻道延迟。 (关于这个问题的一些其他答案更详细地介绍了磁盘写入缓存和写入屏障,日志文件系统可以使用它们来避免损坏。)

相关内容