7

我正在编写一个在 Linux 和 FreeBSD 上运行的程序,并且我想确保数据在每个write()返回时都实际写入物理设备上的文件,这样我的数据就不会意外丢失(例如、断电、进程意外中断等)。

根据 OPEN(2) 手册页,在 Linux(高于 2.6)上O_DIRECT是同步的,但可能存在性能问题;在 FreeBSD 上,O_DIRECT不保证同步,也可能有问题。

那么,在 Linux 上,要么保证同步写入,O_DIRECT要么O_SYNC保证同步写入,但哪个性能更好呢?

在 FreeBSD 上,为了保证同步写入,哪个选项具有最佳性能:(1) O_DIRECT+ fsync()(2)O_DIRECT | O_SYNC或 (3)O_SYNC单独?

4

3 回答 3

8

使用当前的硬盘,即使磁盘向操作系统报告写入已完成,也无法保证文件实际上已写入磁盘!这是由于驱动器中的内置缓存。

在 freeBSD 上,您可以通过将kern.cam.ada.write_cachesysctl 设置为 0 来禁用它。这将显着降低写入性能。上次我测量它(ICH-7 芯片组上的 WDC WD5001ABYS-01YNA0 硬盘,FreeBSD 8.1 AMD64),连续写入性能(用 测量)从 75,000,000 字节/秒下降到 12,900,000 字节/秒。dd if=/dev/zero of=/tmp/foo bs=10M count=1000

如果您想绝对确定您的文件已写入;

  • sysctl kern.cam.ada.write_cache=0使用后跟禁用写入缓存camcontrol reset <bus>:<target>:<lun>
  • 使用选项打开文件O_SYNC

笔记:

  • 您的写入性能(在 HDD 上)现在绝对糟糕。
  • 不要使用sync选项挂载分区;这将导致所有I/O(包括读取)同步完成。
  • 不要使用O_DIRECT. 它将尝试完全绕过缓存。这可能也会影响阅读。
于 2013-10-20T19:17:01.373 回答
3

O_DIRECT基本上只存在 Oracle 绕过内核的缓冲区缓存层并进行自己的缓存。它具有不明确的语义,对您可以执行的读取的大小和对齐方式的任意限制,通常不应该使用。O_SYNC应该给你你想要的效果,但是如果没有一个能够抵抗电源故障或崩溃的底层文件系统,它仍然可能不足以满足你的需求。

于 2013-10-18T01:25:53.187 回答
1

那么,在 Linux 上,要么保证同步写入,O_DIRECT要么O_SYNC保证同步写入,但哪个性能更好呢?

这种说法是不正确的,因为正如@roland-smith在至少 Linux 上所提到的,O_DIRECT 不能保证数据已经到达非易失性介质。它可能碰巧在特定环境中提供该保证(例如,直接写入代表具有电池支持的 SCSI 控制器的磁盘的块设备)但在一般情况下您不能依赖这一点(例如写入 ext4 中的文件仅由单个 SATA 硬盘支持的文件系统),至少有以下原因:

  • O_DIRECT在文件系统中的文件上并不能保证在断电崩溃后检索数据所需的元数据已被写入
  • 内核在原始调用完成之前将 I/O 发送到硬件,但 I/O 仅在易失性硬件缓存中

在上述情况下,突然断电意味着您的程序认为 I/O 成功,但实际上并没有。这些天来,Linux open(2) 手册页是这样说的:

标志本身会O_DIRECT努力同步传输数据,但不保证O_SYNC标志会传输数据和必要的元数据。为了保证同步 I/O,O_SYNC除了O_DIRECT. 有关进一步讨论,请参见下面的注释。

在给定的场景中,在 Linux 上,保证每次写入同步写入的唯一方法是使用O_SYNC(这会导致速度下降)或fsync()在每次 I/O 之后执行(这可能会更慢,因为您执行了两次系统调用)。如果我担心速度,我会放弃使用O_SYNC,而是尽可能大批量写入,然后fsync()在一批之后写入。另请注意,如果您担心数据完整性,您必须检查所有fsync()和所有write()调用(close()等)的返回码是否有错误。

请参阅“O_DIRECT 的真正含义是什么?”的答案。了解更多详情和链接。

在 FreeBSD 上,为了保证同步写入,哪个选项具有最佳性能:(1) O_DIRECT+ fsync()(2)O_DIRECT | O_SYNC或 (3) O_SYNC单独?

您的情况与 Linux 类似(见上文),但在三个选择中,我认为第三个(O_SYNC单独)会是最快的。FreeBSD open(2) 手册页这样说O_DIRECT

O_DIRECT 可用于最小化或消除读取和写入的缓存影响。系统将尝试避免缓存您读取或写入的数据。如果它不能避免缓存数据,它将最小化数据对缓存的影响。如果不小心使用,使用此标志会大大降低性能。

一般注意事项:使用O_DIRECT并不自动意味着所有 I/O 都会更快 - 这取决于工作负载(I/O 大小、I/O 频率、I/O 是顺序的还是随机的、同步发生的频率,因为它可以影响合并等)以及如何提交 I/O(同步与异步)。

于 2020-07-29T06:40:21.280 回答