我正在编写一些软件来处理非常关键的数据,并且需要知道我需要做些什么来实现持久性 .
我看的每个地方都是矛盾的信息,所以我很欣赏任何见解 .
我写入磁盘有三种方法 .
-
使用O_DIRECT | O_DSYNC,pread'ing然后pwrite'ing 512字节 - 16 MB块 .
-
使用O_DIRECT,pread'ing然后pwrite'ing 512字节块,并根据需要定期调用fdatasync .
-
使用内存映射文件,我根据需要定期调用msync(...,MS_SYNC | MS_INVALIDATE) .
这是所有在ext4上的默认标志 .
对于所有这些,数据是否可能丢失(写入或同步返回后)或由于电源故障,恐慌,崩溃或其他任何原因而损坏?
如果我的服务器在pwrite中间,或者在pwrite的开头和fdatasync的结尾之间,或者在被更改的映射内存和msync之间,我可能会混合旧数据和新数据,或者它会是一个还是其他?我希望我的个人pwrite调用是原子的并且是有序的 . 是这样的吗?如果它们跨多个文件就是这种情况吗?所以,如果我用O_DIRECT |写O_DSYNC到A,然后是O_DIRECT | O_DSYNC到B,我保证,无论发生什么,如果数据在B中,它也在A中?
fsync甚至可以保证数据的写入吗? This说没有,但我不知道从那时起事情是否发生了变化 .
ext4的日志记录是否完全解决了this SO answer所说的腐败块的问题?
我目前通过调用posix_fallocate然后ftruncate来增长文件 . 这些都是必要的,它们是否足够?我认为ftruncate实际上会初始化已分配的块以避免these issues .
为了给混音添加混乱,我在EC2上运行它,我不知道这是否会影响任何东西 . 虽然它很难测试,因为我无法控制它被关闭的积极程度 .
2 回答
绝对 .
不是 . 答案取决于设备,可能依赖于文件系统 . 不幸的是,该文件系统可能是"actual"存储设备上方的层和层 . (例如
md
,lvm
,fuse
,loop
,ib_srp
等) .确实如此 . 但你可能仍然可以使用NMI或
sysrq-trigger
来创建一个非常突然停止 .(2018年,首次提出这个问题多年后)
从阅读你的问题,我发现你和磁盘之间有一个文件系统 . 所以问题就变成了:
您可以做的最好(在一般文件系统和未指定的硬件情况下)是“ fsync dance ”,它是这样的:
(从the comment Andres Freund (Postgres Developer) left on LWN无耻地被盗)和你 must check the return code of every call 然后继续查看它是否成功并假设出现问题,如果任何返回代码返回非零 . 如果你正在使用
mmap
那么msync(MS_SYNC)
相当于fsync
.在Dan Luu's "Files are hard"(它有一个关于覆盖各种文件系统的原子性的漂亮表),LWN article "Ensuring data reaches disk"和Ted Ts'o's "Don’t fear the fsync!"上提到了与上面类似的模式 .
是的,您可能没有注意到损坏,因为"allocating writes" due to growing the file past its current bounds can cause metadata operations并且您没有检查元数据持久性(仅数据持久性) .
由于中断覆盖的情况下数据的状态未定义 it could be anything ...
在fsync之间可能会发生重新排序(例如,如果
O_DIRECT
无声地回归到缓冲) .你遇到了更多麻烦 . 为了解决这个问题,您需要编写自己的日记,并可能使用文件重命名 .
没有 .
是的(使用现代Linux和真实的磁盘堆栈,假设没有错误) .
没有 .
(ETOOMANYQUESTIONS)
是的,Linux软件堆栈可能有问题,或者硬件可能有问题(或者说它无法备份),但这并不能阻止上述情况,如果一切都达到最终状态,您可以做到最好 . 在POSIX文件系统上讨价还价 . 如果您知道某个特定操作系统具有特定的文件系统(或没有文件系统)和特定的硬件设置,那么您可以减少对上述某些操作的需求,但通常您不应该跳过任何步骤 .
额外答案:单独使用
O_DIRECT
无法保证与文件系统一起使用时的持久性(初始问题是"how do you know metadata has been persisted?") . 有关这一点的讨论,请参见"Clarifying Direct IO's Semantics" in the Ext4 wiki .