那么,在 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(同步与异步)。