Elo*_*off 39 crash database-design acid
澄清问题:
当OS发送命令将扇区写入磁盘时它是原子的吗?即,如果电源在写入命令之后立即失败,则新数据的写入将完全成功或旧数据保持不变.我不关心多扇区写入会发生什么 - 撕裂的页面是可以接受的.
老问题:
假设您在磁盘上有旧数据X,您在其上写入新数据Y,并且在写入期间树落在电源线上.如果没有花哨的UPS或备用电池的磁盘控制器,最终可能会出现页面撕裂的情况,磁盘上的数据是X部分和Y部分.您是否最终会遇到磁盘上的数据是X部分,Y部分的情况和部分垃圾?
我一直在努力理解像数据库这样的ACID系统的设计,而且我的天真想法似乎是firebird,它不使用预写日志,依赖于给定的写入不会破坏旧数据(X) - 只能完全写入新数据(Y).这意味着如果要覆盖X的一部分,则只能更改被覆盖的X部分,而不是我们打算保留的部分X.
为了澄清,这意味着如果你有一个页面大小的缓冲区,说4096个字节,充满了一半Y,一半X,我们要保持 - 我们告诉OS编写过X该缓冲区,有严重的磁盘的任何事都不短在写入期间我们想要保留的半X被破坏的失败.
Way*_*rad 20
我认为撕裂的页面不是问题.据我所知,所有驱动器都有足够的电量存储,以便在电源故障时完成当前扇区的写入.
问题是每个人都撒谎.
至少当数据库知道事务何时被提交到磁盘时,每个人都会撒谎.数据库发出fsync,操作系统仅在所有未完成的写入已提交到磁盘时返回,对吧?也许不吧.通常,特别是对于RAID卡和/或SATA驱动器,您的程序会被告知所有已提交的内容(即fsync返回),但驱动器上尚未存在数据.
您可以尝试使用Brad的磁盘检查程序来确定您要用于数据库的平台是否能够在不丢失数据的情况下继续使用插件.底线:如果diskchecker失败,则该平台对于运行数据库是不安全的.具有ACID的数据库依赖于知道何时将事务提交到后备存储以及何时尚未提交.无论数据库是否使用预写登录,都是如此(如果数据库在没有完成fsync的情况下返回给用户,则在发生故障时可能会丢失事务,因此它不应声称它提供了ACID语义).
Postgresql邮件列表上有一个讨论持久性的长线程.它开始谈论SSD,但随后它进入了SATA驱动器,SCSI驱动器和文件系统.您可能会惊讶地发现您的数据可能会丢失.对于拥有需要持久性的数据库的人来说,这是一个很好的线程,而不仅仅是那些运行Postgresql的人.
Ano*_*non 20
传统(SCSI、ATA)磁盘协议规范并不能保证在突然断电的情况下任何/每个扇区写入都是原子的(但请参阅下面对 NVMe 规范的讨论)。然而,似乎默契地同意非古代“真实”磁盘悄悄地尽力提供这种行为(例如,Linux 内核开发人员Christoph Hellwig在 2017 年的演示文稿“Linux 的故障-原子文件更新”中立即提到了这一点)。
当涉及到合成磁盘(例如网络附加块设备、某些类型的 RAID 等)时,情况就不太清楚了,它们可能会或可能不会提供扇区原子性保证,同时按照其给定的规范合法行事。想象一个 RAID 1 阵列(没有日志)由一个磁盘组成,该磁盘提供 512 字节大小的扇区,但另一个磁盘提供 4KiB 大小的扇区,从而迫使 RAID 公开 4KiB 的扇区大小。作为一个思想实验,您可以构建一个场景,其中每个单独的磁盘都提供扇区原子性(相对于其自己的扇区大小),但 RAID 设备不会面临断电。这是因为这取决于 512 字节扇区磁盘是否是 RAID 正在读取的磁盘,以及 8 个 512 字节扇区中有多少会在断电前写入 4KiB RAID 扇区。
有时规范提供原子性保证,但仅适用于某些写入命令。SCSI 磁盘规范就是一个例子,可选WRITE ATOMIC(16)命令甚至可以提供超出扇区的保证,但可选命令很少实现(因此很少使用)。更常见的实现COMPARE AND WRITE也是原子的(也可能跨多个扇区),但它对于 SCSI 设备也是可选的,并且具有与普通写入不同的语义...
奇怪的是,由于 Linux 内核开发人员 Matthew Wilcox ,NVMe 规范的编写方式是为了保证扇区原子性。符合该规范的设备必须提供扇区写入原子性的保证,并且可以选择提供高达指定限制的连续多扇区原子性(请参阅该AWUPF字段)。但是,如果您目前无法发送原始 NVMe 命令,则不清楚如何发现和使用任何多部门保证...
Andy Rudoff 是一位工程师,他谈到了他对写入原子性主题所做的调查。他的演讲“从自身保护软件:用于块写入的电源故障原子性”(幻灯片)有一段视频,其中他谈到了电源故障如何影响传统存储上的动态写入。他描述了他如何联系硬盘制造商关于“磁盘的旋转能量用于确保在面临断电情况下完成写入”的声明时的情况。“但答复并未明确表示该制造商是否确实执行了此类操作。此外,没有制造商会说撕裂写入从未发生过,而当他在 Sun 时,ZFS 向块添加了校验和,这导致他们发现了撕裂的情况在测试期间写入。虽然这并不全是惨淡的 - Andy 谈到扇区撕裂是如何罕见的,如果写入被中断,那么您通常只会得到旧扇区,或者只有新扇区,或者一个错误(所以至少损坏不是沉默的) ). Andy 还有一个较旧的幻灯片 Write Atomicity and NVM Drive Design收集了流行的声明并警告说,许多软件(包括多个操作系统上的各种流行文件系统)实际上在不知不觉中依赖于原子性的扇区写入......
(以下内容以 Linux 为中心,但许多概念适用于未部署在严格控制的硬件环境中的通用操作系统)
回到 2013 年,BtrFS 首席开发人员 Chris Mason 谈到(现已解散)Fusion-io 如何创建实现原子操作的存储产品(当时 Chris 正在为 Fusion-io 工作)。Fusion-io 还创建了一个专有文件系统“DirectFS”(由 Chris 编写)来公开此功能。该MariaDB的开发实施,可以通过不再做双缓冲采取的这种行为优势模式导致“每秒43%以上的交易和一半的存储设备上的磨损。” Chris 提出了一个补丁,以便通用文件系统(例如 BtrFS)可以通过新标志O_ATOMIC宣传它们提供原子性保证,但也需要更改块层。说过克里斯在后来添加了一个功能的补丁系列中也提出了块层更改blk_queue_set_atomic_write()。但是,这两个补丁系列都没有进入主线 Linux 内核,并且(当前 2020 年)主线 5.7 Linux 内核中没有O_ATOMIC标志。
在我们进一步讨论之前,值得注意的是,即使较低级别不提供原子性保证,只要知道写入何时达到稳定存储,较高级别仍然可以为其用户提供原子性(尽管有性能开销) . 如果 fsync()可以告诉您何时在稳定存储上写入(POSIX 技术上不保证,但现代 Linux 的情况)然后因为 POSIX 重命名是原子的,您可以使用 create new file/fsync/rename dance 进行原子文件更新,从而允许应用程序执行双缓冲/预写日志本身。堆栈中的另一个示例是写时复制文件系统,如 BtrFS 和 ZFS。这些文件系统为用户空间程序提供了“所有旧数据”或“所有新数据”的保证,因为它们的语义即使磁盘许多不提供原子写入,在大小大于一个扇区的崩溃后也是如此。您可以将这个想法一直推到基于 NAND 的 SSD的磁盘本身 LBA 的数据现在在哪里。
继续我们删节的时间线,2015 年,惠普研究人员写了一篇关于在 Linux 文件系统中引入新功能到 AdvFS(AdvFS 最初是 DEC 的 Tru64 的一部分)中的应用程序数据失败原子更新(PDF)(媒体)的论文:
如果使用新
O_ATOMIC标志打开文件,其应用程序数据的状态将始终反映最近成功的 msync、fsync 或 fdatasync。AdvFS 还包括一项新syncv操作,可将多个文件的更新合并到一个故障原子包 [...]
2017 年,Christoph Hellwig为 XFSO_ATOMIC编写了实验性补丁,以提供. 在“Linux 的故障原子文件更新”演讲(幻灯片)中,他解释了他如何从 2015 年的论文(但没有多文件支持)中汲取灵感,并且补丁集扩展了已经存在的 XFS 引用链接工作。然而,尽管有最初的邮件列表帖子,但在撰写本文时(2020 年年中),此补丁集不在主线内核中。
在 2019 年 Linux Plumbers Conference 的数据库跟踪期间,MySQL 开发人员Dimitri Kravtchuk 询问是否有计划支持O_ATOMIC(链接指向拍摄讨论的开始)。那些组装者提到了上面的 XFS 工作,英特尔声称他们可以在 Optane 上实现原子性,但 Linux 没有提供公开它的接口,谷歌声称在 GCE 存储上提供 16KiB 原子性1。另一个关键点是,许多数据库开发人员需要大于 4KiB 的原子性以避免必须进行双重写入——PostgreSQL 需要 8KiB,MySQL 需要 16KiB,显然 Oracle 数据库需要 64KiB。此外,Richard Hipp 博士(SQLite 数据库的作者)询问是否有标准接口来请求原子性,因为今天SQLite 利用 F2FS 文件系统通过自定义ioctl()s进行原子更新的能力,但 ioctl 绑定到一个文件系统。Chris 回答说,暂时没有任何标准,也没有提供O_ATOMIC接口。
TLDR;如果您严格控制从应用程序一直到物理磁盘的整个堆栈(因此您可以控制和限定整个堆栈),您可以安排使用磁盘原子性所需的内容。如果您不在那种情况下或者您在谈论一般情况,则不应依赖扇区写入是原子的。
当操作系统发送将扇区写入磁盘的命令时,它是原子的吗?
在撰写本文时(2020 年年中):
内核发送的扇区写入可能是原子的(假设扇区不大于 4KiB)。在受控情况下(电池支持的控制器、声称支持原子写入的 NVMe 磁盘、供应商已向您保证的 SCSI 磁盘等),只要不恢复到缓冲状态,用户空间程序就可以使用,I /O 没有在块层分开/合并/您正在发送特定于设备的命令并绕过块层。然而,在一般情况下,内核和用户空间程序都不能安全地假设扇区写入原子性。O_DIRECTO_DIRECT
您是否会遇到磁盘上的数据是部分 X、部分 Y 和部分垃圾的情况?
从规范的角度来看,如果您谈论的是 SCSI 磁盘执行常规 SCSIWRITE(16)并且在写入过程中发生电源故障,那么答案是肯定的:一个扇区可能包含部分 X、部分 Y 和部分垃圾。进行中写入期间的崩溃意味着从正在写入的区域读取的数据是不确定的,磁盘可以自由选择从该区域返回的数据。这意味着所有旧数据、所有新数据、一些旧数据和新数据、全零、全 1、随机数据等都是为所述扇区返回的“合法”值。来自SBC-3 规范的旧草案:
4.9 写入失败
如果一个或多个执行写操作的命令在任务集中并且在断电时正在处理(例如,导致应用程序客户端的供应商特定命令超时)或发生介质错误或硬件错误(例如,因为可移动介质被错误卸载),由这些命令写入的逻辑块中的数据是不确定的。当被执行读取或验证操作的命令访问时(例如,在通电之后或在安装可移动介质之后),设备服务器可以在那些逻辑块中返回旧数据、新数据或供应商特定数据。
在读取遇到此类故障的逻辑块之前,应用程序客户端应重新发出任何执行未完成写入操作的命令。
1 2018 年,Google 宣布已调整其云 SQL 堆栈,这允许他们使用 16k 原子写入 MySQL 和innodb_doublewrite=0via O_DIRECT... Google 执行的底层定制被描述为在虚拟化存储、内核、virtio 和 ext4 文件系统层. 此外,不再提供标题为 16 KB 永久磁盘和 MySQL 的最佳实践(存档副本)的测试版文档描述了最终用户必须做什么才能安全地使用该功能。更改包括:使用合适的 Google 提供的 VM、使用专门的存储、更改块设备参数以及精心创建具有特定布局的 ext4 文件系统。但是,在 2020 年的某个时候,该文档从 GCE 的在线指南中消失了,表明不支持此类最终用户调整。
Elo*_*off 17
似乎没有人同意这个问题.所以我花了很多时间尝试不同的Google查询,直到我终于找到答案.
来自Stephen Tweedie博士,RedHat员工和Linux内核文件系统以及虚拟内存开发人员在这里谈论ext3(他开发的)成绩单.如果有人知道,那就是他.
"仅仅将这些东西写入期刊是不够的,因为期刊中必须有一些标记说:嗯,(实际上有这个期刊记录)这个期刊记录实际上代表了磁盘的完全一致性吗?这样做的方法是通过一些原子操作来标记事务在磁盘上完成"[23m,14s]
"现在,磁盘这些天实际上已经做出了这些保证.如果你开始对磁盘进行写操作,那么即使电源在该扇区写入中间失败,磁盘也有足够的可用功率,它实际上可以从磁盘中窃取电源.主轴的旋转能量;它有足够的功率来完成正在写入的扇区的写入.在所有情况下,磁盘都能保证." [23m,41s]
不,他们不是.更糟糕的是,在默认设置下,磁盘可能会说谎,并且说数据实际上是在磁盘缓存中写入的.出于性能原因,这可能是合乎需要的(实际耐用性要慢一个数量级),但这意味着如果断电并且磁盘缓存没有物理写入,则数据将消失.
不幸的是,真正的持久性既困难又缓慢,因为每次写入需要至少进行一次完整旋转,或者使用日志/撤消进行2次以上.这限制了您每秒几百个数据库事务,并且需要在相当低的级别禁用写入缓存.
因为尽管实际的目的,不同的是不在于在大多数情况下,大的交易.
如果断电,人们似乎不同意扇区写入期间发生的事情.也许是因为它取决于所使用的硬件,甚至是文件系统.
来自维基百科(http://en.wikipedia.org/wiki/Journaling_file_system):
某些磁盘驱动器可确保在电源故障期间写入原子性.然而,其他人可能会在电源丢失后停止在扇区中途写入,从而使其与错误纠正码不匹配.因此该部门腐败,其内容丢失.物理日志可以防止这种腐败,因为它拥有该部门的完整副本,它可以重播下次装载时的腐败.
似乎暗示某些硬盘驱动器无法完成该扇区的编写,但是日志文件系统可以像xlog保护数据库一样保护您免受数据丢失.
从linux内核邮件列表中讨论ext3日志文件系统:
在任何情况下,坏扇区校验和都是硬件错误.扇区写入应该是原子的,它发生与否.
我倾向于相信维基评论.实际上,没有xlog的数据库(firebird)的存在意味着扇区写入是原子的,它不能破坏你不想改变的数据.
有相当多的讨论,这里大约部门的原子写入,再没有达成协议.但是那些不同意的人似乎在谈论多扇区写入(在许多现代硬盘驱动器上并不是原子的.)那些说扇区写入是原子的人似乎更多地了解他们所谈论的内容.
第一个问题的答案取决于所涉及的硬件.至少对于一些较旧的硬件,答案是肯定的 - 电源故障可能导致垃圾被写入磁盘.然而,大多数当前的磁盘都有一些内置于磁盘本身的"UPS" - 一个足够大的电容器足以为磁盘供电足够长的时间,以便将磁盘缓存中的数据写入磁盘盘片.它们还具有检测电源是否仍然良好的电路,因此当电源变得不稳定时,它们将缓存中的数据写入盘片,并忽略它们可能接收到的垃圾.
就"撕裂的页面"而言,典型的磁盘只接受命令来一次写入整个扇区,因此您将获得的内容通常是正确写入的整数扇区,而其他扇区保持不变.但是,如果您使用的逻辑页大小大于单个扇区,那么您最终可能会得到一个部分写入的页面.
然而,这主要适用于直接连接到普通移动盘式硬盘.几乎所有其他事情,规则可以而且往往会有所不同.仅举一个明显的例子,如果您是通过网络编写的,那么您将主要使用正在使用的网络协议.如果通过TCP传输数据,则将拒绝与CRC不匹配的数据,但可能会接受通过UDP传输的具有相同损坏的相同数据.
| 归档时间: |
|
| 查看次数: |
7418 次 |
| 最近记录: |