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

时间:2012-10-20 15:59:44

标签: linux posix mmap fsync durability

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

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

我写入磁盘的方式有三种。

  • 使用O_DIRECT | O_DSYNC,pread'ing然后pwrite'ing 512字节--16 MB块。

  • 使用O_DIRECT,pread'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 个答案:

答案 0 :(得分:3)

  

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

绝对

  

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

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

  

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

这是真的。但你可能仍然可以使用NMI或sysrq-trigger来创建一个非常突然的停止。

答案 1 :(得分: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文件系统上完成,就可以做到。如果您知道具有带有特定文件系统(或没有文件系统)和特定硬件设置的特定操作系统,那么确实可以减少对某些上述内容的需求,但总的来说,您不应跳过任何步骤。 / p>

红利答案: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 pageLWN 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

因此,帖子的结论很复杂:

  • 至少要覆盖非越野车I / O堆栈情况,fsync舞蹈是必要的(即使并不总是足够的)
  • 如果您通过直接I / O执行(写入)I / O,则当写入错误时您将能够获得准确的错误
  • 当通过fsync来获取错误时,较早的内核(早于4.16)是错误的。
相关问题