我正在编写一些软件来处理非常关键的数据,并且需要知道我需要做些什么来实现持久性。
我看的每个地方都是矛盾的信息,所以我很欣赏任何见解。
我写入磁盘有三种方法。
这是所有在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上运行它,我不知道这是否会影响任何东西。虽然它很难测试,因为我无法控制它被关闭的积极程度。
对于所有这些,数据是否可能丢失(写入或同步返回后)或由于电源故障,恐慌,崩溃或其他任何原因而损坏?
绝对。
fsync甚至可以保证数据的写入吗?这不是说,但我不知道从那时起事情是否发生了变化。
不是。答案取决于设备,可能依赖于文件系统。不幸的是,该文件系统可以是“实际”存储设备上方的层和层。 (例如md
,lvm
,fuse
,loop
,ib_srp
等)。
虽然它很难测试,因为我无法控制它被关闭的积极程度。
确实如此。但你可能仍然可以使用NMI或sysrq-trigger
创建一个非常突然停止。
(2018年,首次提出这个问题多年后)
在Linux上持久耐用需要什么?
从阅读你的问题,我发现你和磁盘之间有一个文件系统。所以问题就变成了:
使用Linux文件系统持久耐用需要什么?
您可以做的最好(在一般文件系统和未指定的硬件情况下)是“fsync dance”,它是这样的:
preallocate_file(tmp);fsync(tmp);fsync(dir);rename(tmp, normal);fsync(normal);fsync(dir);
(从the comment Andres Freund (Postgres Developer) left on LWN无耻地窃取)你必须检查每个调用的返回代码,然后继续查看它是否成功并假设出现错误,如果任何返回代码返回非零。如果你正在使用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!"上提到了与上面类似的模式。
对于所有这些[
O_DIRECT
|O_DSYNC
,O_DIRECT
+fdatasync
,mmap
+msync
],数据是否可能丢失(写入或同步返回后)或因电源故障,恐慌,崩溃或其他任何原因而损坏?
是的,您可能没有注意到腐败,因为"allocating writes" due to growing the file past its current bounds can cause metadata operations并且您没有检查元数据持久性(仅数据持久性)。
如果我的服务器在pwrite中间,或者在pwrite的开头和fdatasync的结尾之间,或者在被修改的映射内存和msync之间,我将混合使用旧数据和新数据,[等]
由于在中断覆盖的情况下数据的状态是不确定的,它可能是任何东西......
我希望我的个人pwrite调用是原子的并且是有序的。是这样的吗?
在fsync
之间可能会发生重新排序(例如,如果O_DIRECT
无声地回归缓冲)。
如果他们跨多个文件?
你遇到了更多麻烦。为了解决这个问题,您需要编写自己的日记,并可能使用文件重命名。
如果我用O_DIRECT |写O_DSYNC到A,然后是O_DIRECT | O_DSYNC到B,
没有。
fsync甚至可以保证数据的写入吗?
是 确定上述内容是必要的(如果还不够)(使用现代Linux和假设没有错误的真实磁盘堆栈)。
ext4的日志记录是否完全解决了损坏块的问题
没有。
(ETOOMANYQUESTIONS)
是的,Linux软件堆栈可能是错误的(2019:见下面的附录)或者硬件可能是错误的(或者说它无法备份)但是这并不能阻止上述是你能做到的最好的事情。在POSIX文件系统上,一切都达到了讨价还价的目的。如果您知道某个特定操作系统具有特定的文件系统(或没有文件系统)和特定的硬件设置,那么您可以减少对上述某些操作的需求,但通常您不应该跳过任何步骤。
额外答案:单独使用O_DIRECT
时无法保证与文件系统一起使用时的持久性(最初的问题是“您如何知道元数据是否已被保留?”)。有关这一点的讨论,请参见"Clarifying Direct IO's Semantics" in the Ext4 wiki。
即使使用当前(在编写5.0时)Linux内核fsync
并不总是看到错误通知和4.16之前的内核更糟糕。 PostgreSQL人员发现错误通知可能丢失,未写入的页面标记为干净,导致fsync
返回成功的情况,即使有(吞下)错误异步写回数据(大多数Linux文件系统不能可靠地保存脏数据)一旦失败发生,所以反复“重试”失败的fsync
并不一定表明你可能会发生什么。有关详细信息,请参阅PostgreSQL Fsync Errors wiki page LWN PostgreSQL's fsync() surprise文章和FOSDEM 2019的How is it possible that PostgreSQL used fsync incorrectly for 20 years, and what we'll do about it谈话。
所以帖子结果是很复杂的:
fsync
舞蹈是必要的(即使它并不总是足够)至少覆盖非bug I / O堆栈案例fsync
获取错误的时候出现了问题