【问题标题】:is write() with O_DIRECT ACID compliant?符合 O_DIRECT ACID 的 write() 吗?
【发布时间】:2012-03-14 01:51:47
【问题描述】:

我的数据库引擎通过发出整个磁盘块的 write() 系统调用来写入 64 字节的记录。设备以 O_DIRECT 模式打开。例如,块中的第三条记录从第 128 个字节开始,到第 192 个位置结束,当我执行 UPDATE 时,整个磁盘块(默认为 512 个字节)被写入。

我的问题是,如果每次 UPDATE 发生时我都在自身上写入记录,我可以校准 ACID 合规性吗?通常数据库引擎分两步执行此操作,将修改后的磁盘块写入另一个(空闲)位置,然后在第一次写入返回成功后立即使用一次(原子)写入将索引更新到新块。但我没有这样做,我正在用新的数据覆盖当前数据,期望写入成功。我的方法有任何潜在的问题吗?是否符合 ACID 标准?如果硬件只写入块的一半,而我的记录正好在中间怎么办?还是硬件已经完成了我描述的两步编写过程,但是在块级别,所以我不需要在软件中重复相同的过程?

(注意:没有记录大于物理磁盘块(默认为 512 字节)并且 fsync 在每次 write() 之后进行,这仅适用于 Linux)

【问题讨论】:

标签: linux database-design


【解决方案1】:

ACID 预测失败,并提出处理方法。两阶段提交和三阶段提交是两种相当常见且易于理解的方法。

虽然我是一名数据库专家,但 dbms 让我不必过多考虑这类事情。但我想说的是,在不采取任何其他预防措施的情况下覆盖记录可能会导致“C”和“D”属性(“一致”和“持久”)失败。

要构建真正优秀的代码,假设您的 dbms 服务器没有电池支持的缓存,只有一个电源,并且在事务期间该电源发生了灾难性故障。如果您的 dbms 可以相当干净地应对这种故障,我认为您可以将其称为 ACID 兼容。

稍后。 . .

我阅读了特威迪的成绩单。他不是在谈论数据库直接磁盘访问。他在谈论一个日志文件系统。日志文件系统也执行两阶段提交。

听起来您正试图通过单阶段提交达到 ACID 合规性(在数据库意义上)。我不认为你能逃脱惩罚。

Opening with O_DIRECT 的意思是“尝试尽量减少进出此文件的 I/O 的缓存影响”(强调添加)。我认为您还需要 O_SYNC。 (但链接的内核文档警告说,大多数 Linux 文件系统没有实现 O_SYNC 的 POSIX 语义。而且众所周知,文件系统和磁盘都会在写入是否命中盘片方面撒谎。)

内核文档中还有两个注意事项。首先,“建议应用程序将 O_DIRECT 的使用视为默认禁用的性能选项。”你不这样做。您正在尝试使用它来实现 ACID 合规性。

第二,

“关于 O_DIRECT 一直困扰着我的是 整个界面很愚蠢,可能是由一个 用一些严重的精神控制物质发疯的猴子。”——莱纳斯

SQLite 有一篇关于它们如何处理原子提交的可读论文。 Atomic Commit in SQLite

【讨论】:

  • 我想过你说的但是即使在两阶段提交中,当你开始将请求写入事务日志文件时,你如何确保写入日志文件已完成?例如,您的事务是 64 字节,您将 write() 发送到磁盘,然后电源关闭。磁盘已写入 33 个字节。当电源恢复并读取该扇区时,您如何知道剩余的 31 个字节是否已写入?
  • @Nulik:如果出现故障,重新启动程序将在协调器的日志中查找决策记录。如果找到,则处理从中断处继续。如果不是,则假定回滚。 Date 在他的Introduction to Database Systems 中有几页关于这个详细主题的内容。你也可以阅读PostgreSQL source code
  • 好吧,我实际上找到了问题的答案。磁盘扇区写入似乎是原子的,在这里回答:stackoverflow.com/questions/2009063/…,所以由于我正在编写单个扇区,所以我不应该担心这一点,除非我有一些非常旧的硬件
【解决方案2】:

没有。

您不能假设磁盘写入会成功。而且您不能假设磁盘会将现有数据保留在原处。 Here is some QNX documentation also stating this.

如果你真的非常不走运,磁盘电源将在写入时发生故障,从而使块的校验和损坏和写入一半的数据。

这就是 ACID 系统使用至少两个数据副本的原因。

【讨论】:

  • 根据an earlier SO answer,您错了,至少对于某些(全部?)磁盘......即使电源出现故障也能保证原子单扇区写入。
  • @Nemo:根据个人经验,我知道硬盘驱动器在电源故障事件后会出现坏扇区。也许服务器驱动器可以保证它。西部数据绿色驱动器没有。
【解决方案3】:

write()O_DIRECT 是否符合 ACID?

,一般情况下无法保证。以下是耐久性的一些反例:

  • O_DIRECT 不保证确认的数据会从易失性缓存中取出这是设备的一部分
  • O_DIRECT 不保证文件系统元数据的持久性,可能需要实际读回(确认的)写入数据(例如,在追加写入的情况下)

我的问题是,如果我在每次 UPDATE 发生时都将记录写入自身,我可以校准 [原文如此] ACID 合规性吗?

一般情况下没有。例如,如果在写入过程中发生崩溃,则符合规范的 SCSI 磁盘不必保证仅获取旧数据或仅获取新数据的语义(它返回读取该数据的错误是合法的,直到该区域无条件覆盖)。如果您正在对文件系统中的文件进行写入,那么事情会更加复杂。在发出新的 I/O 之前,在 write() 之后有一个成功的 fsync() 将帮助您知道写入是稳定的,但不足以确保在一般情况下定时断电的原子性(仅旧数据或新数据) .

我的方法 [假设覆盖完全是原子的] 有 [原文如此] 任何潜在问题吗?

是的,见上文。您正在做的事情可能会在某些设置中按您的意愿工作,但不能保证它应该在所有设置中工作(即使根据他们的规范它们是“无故障的”)。

请参阅此answer on "What does O_DIRECT really mean?" 以进行进一步讨论。

【讨论】:

    猜你喜欢
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 2012-02-21
    • 2016-01-31
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多