在Linux上持久耐用需要什么?

问题描述 投票:9回答:2

我正在编写一些软件来处理非常关键的数据,并且需要知道我需要做些什么来实现持久性。

我看的每个地方都是矛盾的信息,所以我很欣赏任何见解。

我写入磁盘有三种方法。

  • 使用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上运行它,我不知道这是否会影响任何东西。虽然它很难测试,因为我无法控制它被关闭的积极程度。

linux posix mmap fsync durability
2个回答
3
投票

对于所有这些,数据是否可能丢失(写入或同步返回后)或由于电源故障,恐慌,崩溃或其他任何原因而损坏?

绝对。

fsync甚至可以保证数据的写入吗?这不是说,但我不知道从那时起事情是否发生了变化。

不是。答案取决于设备,可能依赖于文件系统。不幸的是,该文件系统可以是“实际”存储设备上方的层和层。 (例如mdlvmfuseloopib_srp等)。

虽然它很难测试,因为我无法控制它被关闭的积极程度。

确实如此。但你可能仍然可以使用NMI或sysrq-trigger创建一个非常突然停止。


2
投票

(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_DSYNCO_DIRECT + fdatasyncmmap + 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

附录(2019年3月)

即使使用当前(在编写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堆栈案例
  • 如果通过直接I / O执行(写入)I / O,则在写入错误时可以获得准确的错误
  • 早些时候(早于4.16)内核在通过fsync获取错误的时候出现了问题

另见:

© www.soinside.com 2019 - 2024. All rights reserved.