我正在编写一个在Linux和FreeBSD上运行的程序,我希望确保在每个write()
返回时数据实际写入物理设备上的文件,这样我的数据不会因意外丢失(例如,断电,进程意外中断等)。
根据OPEN(2)手册页,在Linux(高于2.6)上,O_DIRECT
是同步的,但可能存在性能问题;在FreeBSD上,O_DIRECT
不保证同步,也可能有问题。
因此,在Linux上,O_DIRECT
或O_SYNC
保证同步写入,但哪一个具有更好的性能?
在FreeBSD上,为了保证同步写入,哪个选项具有最佳性能:(1){1}} + O_DIRECT
(2)fsync()
或(3)O_DIRECT | O_SYNC
单独?
答案 0 :(得分:5)
使用当前的硬盘,即使磁盘将写入报告为完整的操作系统,也有 no 确保文件实际写入磁盘!这是由于驱动器中的内置缓存。
在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
选项打开文件。注意:
sync
选项装载分区;这将导致所有 I / O(包括读取)同步完成。O_DIRECT
。它会尝试完全绕过缓存。这可能也会影响读取。答案 1 :(得分:3)
O_DIRECT
基本上只存在于Oracle以绕过内核的缓冲区缓存层并进行自己的缓存。它具有不明确的语义,对您可以执行的读取的大小和对齐的任意限制,并且通常不应该使用。 O_SYNC
应该可以为您提供所需的效果,但如果没有能够抵御电源故障或崩溃的基础文件系统,它仍然可能无法满足您的需求。
答案 2 :(得分:0)
因此,在Linux上,
O_DIRECT
或O_SYNC
可以保证同步写入,但是哪个具有更好的性能?
该陈述是不正确的,因为至少在Linux上,mentioned by @roland-smith O_DIRECT
不能保证数据已到达非易失性介质。 可能可以在特定的环境中提供这种保证(例如,直接写入代表具有电池后备SCSI控制器的磁盘的块设备),但是在一般情况下,您不能依赖此保证(例如,至少由于以下原因,写入仅由单个SATA硬盘支持的ext4文件系统中的文件):
O_DIRECT
在文件系统中的文件上并不能保证在写入掉电故障后恢复数据所需的元数据在上述情况下,突然断电意味着您的程序认为I / O成功,而没有成功。这些天Linux open(2) man page这么说:
O_DIRECT
标志本身会尽力同步传输数据,但不能保证O_SYNC
标志能保证数据和必要的元数据已传输。为了保证同步I / O,除了O_SYNC
之外,还必须使用O_DIRECT
。有关更多讨论,请参见下面的注释。
在给定的情况下,在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的方式(同步还是异步)。