mar*_*trz 71 drivers kernel io unix-philosophy
在 Linux 中,诸如cp
或之类的命令的完成执行dd
并不意味着数据已写入设备。例如,必须调用sync
或调用驱动器上的“安全删除”或“弹出”功能。
这种方法背后的哲学是什么?为什么不一次写入数据?是否存在因 I/O 错误而导致写入失败的危险?
fro*_*utz 59
它只是给那些实际上不必等到写入完成的程序一种速度的错觉。以同步模式挂载您的文件系统(这为您提供即时写入)并查看一切运行速度有多慢。
有时文件只是暂时存在......程序会做一些工作并在工作完成后立即删除文件。如果您延迟了这些写入,您可能一开始就没有写入它们。
有没有因为 IO 错误而导致写入失败的危险?
哦,绝对。在这种情况下,通常整个文件系统都会进入只读模式,一切都很糟糕。但这种情况很少发生,总体上失去性能优势毫无意义。
jll*_*gre 47
这种方法背后的哲学是什么?
效率(更好地利用磁盘特性)和性能(允许应用程序在写入后立即继续)。
为什么不一次写入数据?
主要优点是操作系统可以自由地重新排序和合并连续的写入操作以提高其带宽使用率(更少的操作和更少的搜索)。当请求少量大操作时,硬盘性能更好,而应用程序往往需要大量小操作。另一个明显的优化是,当同一块在短时间内多次写入时,操作系统还可以删除除最后一次写入之外的所有内容,或者如果在此期间受影响的文件已被删除,则甚至可以一起删除一些写入。
这些异步写入是在write
系统调用返回后完成的。这是第二个也是用户最明显的优势。异步写入加快了应用程序的速度,因为它们可以自由地继续工作,而无需等待数据实际存在于磁盘上。对于读取操作也实现了相同类型的缓冲/缓存,其中最近或经常读取的块保留在内存中,而不是从磁盘再次读取。
有没有因为 IO 错误而导致写入失败的危险?
不必要。这取决于使用的文件系统和适当的冗余。如果数据可以保存在别处,那么 I/O 错误可能是无害的。像 ZFS 这样的现代文件系统可以自我修复坏的磁盘块。另请注意,I/O 错误不会使现代操作系统崩溃。如果它们在数据访问期间发生,它们会简单地报告给受影响的应用程序。如果它们在结构元数据访问期间发生并使文件系统处于危险之中,则它可能会以只读方式重新挂载或使其无法访问。
在操作系统崩溃、断电或硬件故障的情况下,也存在轻微的数据丢失风险。这就是为什么必须 100% 确定数据在磁盘上的应用程序(例如数据库/金融应用程序)执行效率较低但更安全的同步写入的原因。为了减轻性能影响,许多应用程序仍然使用异步写入,但最终在用户显式保存文件时同步它们(例如 vim、文字处理器)。
另一方面,绝大多数用户和应用程序不需要也不关心同步写入确实提供的安全性。如果发生崩溃或停电,唯一的风险通常是最坏的情况下会丢失最后 30 秒的数据。除非涉及金融交易或类似的事情,这意味着成本远大于 30 秒的时间,否则性能的巨大提升(这不是幻觉而是非常真实的)异步写入在很大程度上优于风险。
最后,同步写入不足以保护无论如何写入的数据。如果您的应用程序真的需要确保它们的数据无论发生什么都不会丢失,则需要在多个磁盘和多个地理位置上进行数据复制,以抵御火灾、洪水等灾难。
Mar*_*ick 26
在 Linux 甚至 Unix 之前,异步缓冲 I/O 就已经被使用了。Unix 拥有它,因此拥有它的所有分支。
以下是 Ritchie 和 Thompson 在他们的 CACM 论文The UNIX Time-Sharing System 中所写的内容:
对于用户来说,文件的读取和写入似乎是同步且无缓冲的。也就是说,在从读取调用返回后,数据立即可用,相反,在写入后,用户的工作区可能会被重用。事实上,系统维护了一个相当复杂的缓冲机制,这大大减少了访问文件所需的 I/O 操作次数。
在您的问题中,您还写道:
有没有因为 IO 错误而导致写入失败的危险?
是的,写入可能会失败并且程序可能永远不会知道它。虽然这从来都不是一件好事,但在 I/O 错误导致系统恐慌的情况下,这种影响可以被最小化(在某些操作系统上,这是可配置的 - 系统可以继续运行而不是恐慌,但受影响的文件系统是卸载或安装为只读)。然后可以通知用户该文件系统上的数据是可疑的。并且可以主动监控磁盘驱动器以查看其增长的缺陷列表是否正在迅速增加,这表明驱动器出现故障。
BSD 添加了fsync
系统调用,因此程序可以在继续之前确定其文件数据已完全写入磁盘,随后的 Unix 系统提供了进行同步写入的选项。GNU dd 有一个选项conv=fsync
可以确保在命令退出之前所有数据都已写出。当写入慢速可移动闪存驱动器时,它会派上用场,其中缓冲数据可能需要几分钟才能写出。
文件损坏的另一个来源是系统突然关闭,例如断电。几乎所有当前系统都在其文件系统中支持干净/脏标志。当没有更多数据要写出并且文件系统即将卸载时,该标志设置为clean,通常是在系统关闭期间或通过手动调用umount
. fsck
如果系统检测到文件系统没有完全关闭,系统通常会在重新启动时运行。
Baa*_*rud 15
许多好的答案,但让我补充一点...请记住,Unix 是一个多进程和多用户系统,因此可能有许多用户会尝试在(几乎)同时。使用旧的慢速硬盘 - 也许安装在网络上 - 这不仅需要时间(程序基本上会锁定并且用户必须等待),而且会导致大量移动读/写头磁盘来回。
因此,等待写入的文件在内存中保留了一段时间,并在它们应该在磁盘上的位置之后排序......以及当缓冲区已满时 - 或者磁盘同步守护进程已经等待所需的秒数(我认为通常约为 30 秒)-整个缓冲区“按顺序”写入磁盘,写入头只需进行一次连续的扫描动作,将文件写入磁盘为它去了……而不是到处跳。
当然,使用今天的快速磁盘——更不用说固态设备——收益要少得多......特别是在家庭 linux 系统上,一次只有一个用户在工作,而且只有几个程序。
无论如何,通过读入(到缓存/缓冲区)超过要求的预期读取的组合 - 以及对等待写入的数据进行排序,以便它可以以“一个动作”写入 - 实际上是一个非常好的主意时间,尤其是在许多用户进行大量读写的系统上。
Bas*_*tch 13
它不是 Linux 特有的,它被称为页面缓存(Linux 做得很好)。另见http://linuxatemyram.com/;所以如果一个文件被写入,然后在几秒钟后再次读取,通常不需要磁盘 I/O。
主要优点是在许多系统上,有很多 RAM,其中一些可以被内核用作缓存。所以一些文件操作可以利用这种缓存。此外,磁盘 I/O 时间比 RAM 慢很多(对于 SDD 通常为数千倍,对于机械硬盘则慢近百万倍)。
应用程序代码可以提供有关此缓存的提示:参见例如posix_fadvise(2)和madvise(2)
转盘比 RAM 慢。我们使用读/写缓存来“隐藏”这个事实。
写 IO 的有用之处在于它不需要立即发生磁盘 IO - 与读取不同,在读取完成之前您无法将数据返回给用户。
因此,写入在软时间约束下运行——只要我们的持续吞吐量不超过磁盘的吞吐量,我们就可以在写入缓存中隐藏许多性能损失。
而且我们确实需要写入缓存 - 旋转磁盘相对来说非常慢。但是,现代 RAID 类型对操作的影响也很大。
以 RAID 6 为例,为了完成一个写 IO 必须:
因此,每次写入实际上是6 次IO 操作——特别是当你有像大 SATA 驱动器这样的慢速磁盘时,这会变得非常昂贵。
但是有一个很好的简单解决方案 - 编写合并。如果您可以在缓冲区中构建“完整条带”写入,则无需从磁盘读取奇偶校验 - 您可以根据内存中的内容进行计算。
这样做是非常可取的,因为那样你就不再有写放大了。实际上,您最终可以得到比 RAID 1+0 更低的写入损失。
考虑:
RAID 6、8+2 - 10 个轴。
连续写入 8 个数据块 - 在缓存中计算奇偶校验,每个磁盘写入一个数据块。每 8 次写入 10 次,意味着写入惩罚为 1.25。RAID 1+0 的 10 个磁盘仍然有 2 的写入惩罚(因为您必须写入每个子镜像)。所以在这种情况下,你实际上可以让 RAID 6 表现得比 RAID1+0 更好。在实际使用中,您会得到更多的混合 IO 配置文件。
因此,写入缓存对 RAID 集的感知性能产生了巨大的影响 - 您可以以 RAM 速度写入并且具有较低的写入损失 - 如果您这样做,可以提高您的持续吞吐量。
如果您不这样做,您将遭受 SATA 的缓慢性能,但将其乘以 6 并在其中添加一些争用。没有写缓存的 10 路 SATA RAID-6 会比没有 RAID 的单个驱动器快一点……但不会快很多。
不过,您确实要冒风险 - 正如您所注意到的 - 断电意味着数据丢失。您可以通过缓存刷新周期、电池后备缓存或使用 SSD 或其他非易失性缓存来缓解这种情况。
归档时间: |
|
查看次数: |
15062 次 |
最近记录: |