数据库不保证任何东西,它们不控制从数据库到存储中的比特的整个堆栈,那么它们怎么能呢?
他们能做的是确保他们调用适当的函数,如果假设成立,将保持持久性。
它的工作方式是程序写入数据库。数据库(通常)将该写入操作转换为日志事件,然后调用 fsync 将日志缓冲区刷新到磁盘。
但是请看,这里涉及到几个抽象。第一个是数据库级别的缓冲。DB 使用适当的信息更新日志缓冲区,然后将这些缓冲区写入某种 I/O 流。
如果它们是使用 stdio 编写的,它再次缓冲数据(不太可能,但谁知道),那么他们将不得不在该流上调用 flush 以强制系统调用将缓冲区“写入磁盘”。
但是,正如您所观察到的,写入“磁盘”意味着写入更多缓冲区。因此,fsync 调用相当于 stdio 的刷新调用。它告诉操作系统将进程数据写入磁盘。但这究竟意味着什么?这意味着操作系统调用适当的设备驱动程序将底层块写入物理设备。
好吧,设备驱动程序可以说“Okey dokey”而不做任何事情。他们通常不会,但他们可以。司机可以为所欲为。我们假设发生的是驱动程序获取数据缓冲区,然后开始通过适当的接口(SATA、SCSI、iSCSI、NFS、USB 等)与硬件通信。
这里的坚果是,到底司机到底在说什么?好吧,今天,使用现代 SATA 驱动器,它正在与另一台计算机通信。这台计算机是磁盘驱动器的控制器。
你知道磁盘驱动器上的控制器是做什么的吗?它们将数据缓冲到 RAM 中。所以,有可能你可以做“一切正确”(stdio flush、fsync、驱动程序写入块设备)并且仍然有数据,在 RAM 中,等待失败,坐在大约 50 美元的硬盘上,上面写着“Aok boss!” .
一些驱动器默认说“okey dokey”并将数据简单地存储在缓冲区中,并且需要另外配置。其他驱动器默认开箱即用。如果您将前一种驱动器(配置不正确)用于数据库或 RAID 系统,那么,如果您断电,您会感到很痛苦。
或者设备将正确配置并愉快地将块写入坏扇区,而您从一开始就注定要失败。这就是生活。
另外,考虑一下您是否正在与驱动程序交谈,与网络交谈,与 SAN 控制器交谈,在写入阵列之前使用电池备份 RAM 缓存......希望如此。
因此,数据库不保证任何事情。相反,他们进行尽职调查,应该将数据安全地传送到实际的物理设备,以及数据最终将实际保存的位置。
任何称其执行 ACID 的数据库都可以做到这一点,并且所有操作系统都支持这一点——当然,任何人都会实际使用的所有操作系统。
底线,如果你想确保你的数据在磁盘上,在 Unix 中,你调用 fsync。在 Windows 中,你称之为“无论谷歌说你在 Windows 上调用 fsync 的东西”。那时实际发生的事情不在你的掌控之中,所以最好向那些了解你的硬件和接口的人提问。然而,程序已经完成。
附加物:
现代数据库通常的工作方式是将数据组织在磁盘上的“表”中,并且通常单独作为“索引”进行组织。因此,您可以想象,如果您有一个包含 1000 行的表,它以 100 个“页”存储在磁盘上,您可以看到如果更新了第 500 行,您将需要更新第 50 页。您还可以看到,如果您更新了第 700、500、600 行,则需要更新第 70、50 和 60 页。
好吧,事实证明,磁盘驱动器作为流媒体设备工作得非常快。当您必须移动磁盘磁头(在驱动器上来回移动的手臂)时,它会显着减慢速度。所以你可以在上面的例子中看到,磁盘磁头在写操作期间来回弹跳。
现在,具有事务的数据库也需要某种日志。日志是记录所有操作的地方。日志通常也仅附加到,因此如果您要更新上面的那些行,它们将作为 3 个连续事件在日志中被捕获。
所以DB所做的是,当你改变一行时,它会更新内部缓冲区,即第50页的内部副本。当数据库想要去获取第 500 行的另一个副本时,它会看到它已经在 RAM 中有一个副本,并且不需要去磁盘。一旦它更新了内部缓冲区,它就会将操作正确地写入日志。由于这些是顺序的,因此它们要快得多。最后,它将使用 fsync 等提交写入。每次提交事务时,它都会立即执行此操作。在您“确定”数据记录在某处之前,您无法提交事务。
此时,内存中有行,日志中捕获的行(持久),但磁盘上的实际页面已过期。对于正在运行的数据库,这不是问题。最终,系统将“检查点”。这需要所有过期的日志条目,并将它们复制到磁盘上的最终目的地,同步日志、缓冲区和磁盘。当它这样做时,它将对磁盘的写入进行排序。所以上面不是写第 60 页,然后是第 50 页,然后是第 70 页,而是按顺序写它们:50、60、70。更少的寻头,更好的性能。
现在,如果系统在此之前崩溃,那没问题。我们已经将数据安全地保存在日志中。因此,当系统恢复正常时,它会进入“恢复”状态。恢复基本上是对日志中已提交的所有数据(即它们的事务已完成)运行检查点过程,并像以前一样将它们刷新到磁盘页面。它会在让数据库出现并可以访问之前执行此操作。
至于配置驱动器,据我了解,有一些实用程序可以将参数配置写入驱动器。取决于操作系统,我真的不知道细节。你必须用谷歌搜索它。