通常情况下,离硬件越近,离现实越远。不仅在M1内核及其性能中可以看到这一点,而且在存储方面也是一个很好的规则。
我一拿到第一台M1 Mac电脑,就对其进行了现成的磁盘基准测试,以比较其内部SSD与iMac Pro的速度。其中一些结果表明,近20 GB/s的传输速率高得离谱,这似乎是缓存的结果。换句话说,SSD欺骗了测试,使其无法测量向磁盘写入数据的速率,而只是将数据传输到高速缓存中,写入本身会在一段时间后更慢地进行。
经过大量的实验和测试,我开发出了自己的基准测试应用程序Stibium,它在各种SSD上都给出了相当可靠的结果。
缓存和磁盘性能问题最近在M1 Mac上再次出现,这一次是在朝日Linux的开发中。因为它在M1机型上运行,而不是在虚拟机上运行,所以它必须自行驱动,为此,赫克托·马丁和他的团队正在深入研究苹果的硬件。这似乎导致了人们对性能和数据完整性之间的权衡的担忧,但最终可能会回到缓存/缓冲区及其刷新的老问题,以及不能确切说出真相的磁盘。
macOS有两种刷新磁盘写入的低级方法:fsync()和fcntl()中的F_FULLFSYNC命令。然而,绝大多数应用程序都没有达到这个水平,让macOS来决定该怎么做。选择很重要,因为它们的工作方式非常不同。fsync()使文件的所有修改数据和元数据都移动到磁盘,并从计算机中刷新。但是,磁盘本身可能会将数据留在自己的缓冲区中一段时间,然后以较慢的速度写入存储器。F_FULLFSYNC做同样的事情,但随后要求磁盘刷新其所有缓冲区,并将数据写入其存储器。
当磁盘执行命令要求的操作时,F_FULLFSYNC通常比fsync()慢得多,正如您所预料的那样。如果您相信fsync()与F_FULLFSYNC的工作原理相同,那么您可能会在磁盘的真正性能上受到严重误导。此外,如果一个磁盘忽略在F_FULLFSYNC上刷新其缓冲区的请求,那么它看起来会比另一个符合要求的磁盘快得多。有趣的是,苹果公司针对后一个命令的手册页指出,“已知某些FireWire驱动器也会忽略刷新其缓冲数据的请求”。
不过,这不仅仅关乎磁盘的性能和市场营销,正如本文所探讨的,刷新行为对文件系统、数据库和可靠性至关重要。
一个简单的例子是,如果磁盘突然断电会发生什么。如果使用fsync()将对文件系统的更改刷新到磁盘上,那么磁盘的缓冲区中很可能仍有这些更改。APFS通过在删除旧数据之前写入新数据,使用写时拷贝来确保突发灾难不会导致其文件系统数据出现问题。由于磁盘缓冲区可能会无序清空,因此在断电时,可能是在从缓冲区写入新数据之前执行了删除操作,或者是后来的新数据被无序写入。正如苹果公司的fsync()文档所述:“这不是一个理论上的边缘案例。这个场景很容易在现实世界的工作负载和驱动器电源故障中重现。”
这就是为什么macOS有F_FULLFSYNC,以及为什么它在其支持的主要文件系统HFS+、FAT、UDF和APFS上实现,根据其手册页。
还有一条重要信息与Mac用户直接相关。如果你转向苹果的旧Time Machine over SMB规范,你会看到一整节关于F_FULLFSYNC的内容,其中指出“Time Machine客户端在定期检查点发出此命令,以确保备份中不会发生数据损坏。”当Time Machine备份到本地存储时,可能也是这样。如果是这样的话,它会让我们放心,它会不遗余力地防止损坏的备份,而且,考虑到F_FULLFSYNC即使在快速本地存储上也会对性能造成影响,它还解释了为什么备份速度会比您希望的慢。
当您试图测量磁盘的性能时,磁盘的缓存行为可能是显而易见的,并可能导致虚假的高传输速率。当您需要可靠性时,它变得最重要,因此macOS确保在APFS、HFS+、FAT和UDF中需要时正确刷新对磁盘的写入。在时间机器编写备份时,它们也会定期出现,以保护它们不受损坏。
我非常感谢@rosyna、@janl和@evntdrvn提供了所有线索;然而,任何错误都是我的错。