【问题标题】:O_DIRECT vs. O_SYNC on Linux/FreeBSDLinux/FreeBSD 上的 O_DIRECT 与 O_SYNC
【发布时间】:2013-10-18 01:20:43
【问题描述】:

我正在编写一个在 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 单独?

【问题讨论】:

  • 我认为你根本无法比较这些,因为它们是根本不同的东西(即使它们似乎做类似的事情)。

标签: c linux freebsd


【解决方案1】:

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

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

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

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

注意:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 谢谢。关于性能,O_DIRECT 和 O_SYNC 哪个性能更好?
    • 除非您编写自己的缓存层(甚至可能如此),否则O_DIRECT 的性能非常糟糕,因为它每次都会从磁盘重新读取。
    【解决方案3】:

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

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

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

    在上述情况下,突然断电意味着您的程序认为 I/O 成功,但实际上并没有。这几天Linux open(2) man page 这么说:

    O_DIRECT 标志本身会努力同步传输数据,但不提供O_SYNC 标志的保证,即传输数据和必要的元数据。为了保证同步 I/O,除了O_DIRECT 之外,还必须使用O_SYNC。有关进一步讨论,请参阅下面的注释。

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

    有关更多详细信息和链接,请参阅此answer on "What does O_DIRECT really mean?"。

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

    您的情况与 Linux 类似(见上文),但在三个选择中,我认为第三个(仅O_SYNC)最快。 FreeBSD open(2) man page 这么说O_DIRECT:

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

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

    【讨论】:

      猜你喜欢
      • 2021-04-25
      • 2011-06-30
      • 1970-01-01
      • 2020-11-23
      • 2013-04-06
      • 1970-01-01
      • 1970-01-01
      • 2020-02-12
      • 1970-01-01
      相关资源
      最近更新 更多