为什么SQL数据库使用预写式日志而不是命令日志?

58
我读到了关于Voltdb的命令日志。命令日志记录事务调用,而不是像预写式日志中每行更改那样。通过仅记录调用,命令日志被保持到最小限度,限制磁盘I/O对性能的影响。
有人可以解释一下为什么Voltdb使用命令日志以及标准的SQL数据库(如Postgres、MySQL、SQLServer、Oracle)为什么使用预写式日志吗?请阐述背后的数据库理论。

2
Voltdb 如何实现“撤销”功能?如果我执行 UPDATE some_table SET some_column=2,那么仅仅知道这个命令是不允许我回滚更改的吗? - Martin Smith
1
在电源故障的情况下,它也是一种可靠的手段来识别不完整的数据库写入。 - Hugh Jones
@MartinSmith,回答你的问题:最新的快照+从那个时间开始的命令重放。http://voltdb.com/docs/graphics/CmdLogPicture.png - Renat Gilmanov
1
VoltDB不会并发运行命令,它会从队列中运行单个命令直到完成 - 因此命令日志就足够了 - 如果您“重新运行”命令日志,则会将数据库的状态恢复到最后一个命令运行的点 - 在并发情况下,情况并非如此 - 命令会交错运行! - Vérace
6个回答

92
我认为最好改为:

新的分布式 VoltDB 为什么使用命令日志而不是预写式日志?

让我们进行一个实验,想象一下你要编写自己的存储/数据库实现。毫无疑问,您已经足够先进,可以抽象出文件系统,并使用块存储以及一些额外的优化。

一些基本术语:

  • 状态: 在给定时间点存储的信息
  • 命令: 指示存储更改其状态的指令

因此,您的数据库可能如下所示:

enter image description here

下一步是执行一些命令:

enter image description here

请注意以下几个重要方面:
  1. 一个命令可能会影响许多存储实体,因此许多块将变得脏
  2. 下一个状态是当前状态和命令的函数
一些中间状态可以被跳过,因为只需要有一系列的命令。

enter image description here

最后,您需要确保数据完整性。
  • 预写式日志(Write-Ahead Logging) - 简要概念是在任何对永久存储进行重大更新之前记录状态更改。按照我们的想法,我们可以为每个块记录增量更改。
  • 命令日志(Command Logging) - 简要概念是仅记录用于生成状态的命令

enter image description here

两种方法都有优缺点。Write-Ahead日志包含所有更改的数据,Command日志需要额外处理,但快速且轻量。关键在于Command日志记录调用而不是事务结果。仅记录调用可以将命令日志保持到最少,从而限制磁盘I/O对性能的影响。SQLite的传统回滚日志通过将原始的未更改的数据库内容写入单独的回滚日志文件中,然后直接将更改写入数据库文件来工作。当一个特殊记录表示提交被附加到WAL时,提交就会发生。因此,提交可以在不写入原始数据库的情况下发生,这允许读者在同时将更改提交到WAL时继续从原始的未更改的数据库进行操作。VoltDB: Command Logging and Recovery SQLite: Write-Ahead Logging

PostgreSQL: 写前日志(WAL)

使用WAL可大幅减少磁盘写入次数,因为只需将日志文件刷新到磁盘即可保证事务提交,而不是将事务更改的每个数据文件都刷到磁盘。

日志文件按顺序写入,因此同步日志的成本比刷新数据页的成本要低得多。这对于处理许多小事务并涉及数据存储不同部分的服务器尤其如此。此外,当服务器处理许多小型并发事务时,一次fsync日志文件可能足以提交多个事务。

结论

命令记录:

  1. 速度更快
  2. 占用空间更小
  3. "重放"过程更繁重
  4. 需要频繁的快照

写前日志是提供原子性的技术。更好的命令记录性能也应该改善事务处理。1英尺数据库

enter image description here

确认

VoltDB博客:VoltDB命令日志简介

与ARIES风格日志记录相比,命令日志的一个优点是可以在执行之前记录事务,而不是执行事务并等待日志数据刷新到磁盘。另一个优点是命令日志所需的IO吞吐量由中继命令使用的网络限制,并且在Gig-E的情况下,这种吞吐量可以通过廉价的商品磁盘满足。

重要的一点是要记住VoltDB本质上是分布式的。因此,处理事务有些棘手,性能影响是明显的。

VoltDB博客:VoltDB的新命令日志功能

VoltDB的命令日志包括存储过程调用及其参数。每个节点都会创建一个日志,并且每个日志都会被复制,因为所有工作都会被复制到多个节点。这导致了一个可重放的复制命令日志。由于VoltDB事务是强有序的,因此命令日志也包含排序信息。因此,重放可以按照原始事务运行的确切顺序进行,具有VoltDB提供的完整事务隔离性。由于这些调用本身通常比修改的数据小,并且可以在提交之前记录,因此这种方法对性能影响非常小。这意味着VoltDB用户可以获得相同类型的极高性能数字,并获得额外的耐用性保证。

1
使用WAL,读取器从未刷新的日志页面中读取。通过命令记录,您能够从命令日志中读取吗?不行。因此,命令记录非常不同。VoltDB使用命令记录来创建恢复点并确保耐久性。WAL用于确保耐久性,但也用于提高速度。例如,您可以将WAL定位在固态驱动器上,并观察SQLITE性能接近像Volt和Redis这样的内存数据库,同时占用一小部分RAM。 - Erik Aronesty
@ErikAronesty,不太明白你的意思。WAL和CL之间有显著的区别吗?当然,它们都提供了恢复点。那么,重点是什么呢? - Renat Gilmanov
在Volt中是否存在非确定性操作,例如random()?如果有,这样的命令如何表达?我认为它会在接收节点上实现,然后进行复制? - Byron Ruth
你认为我对楼主的评论怎么样? - Vérace

2
使用WAL,读者从未刷新的日志中读取页面。主数据库不进行修改。使用命令日志记录,您无法从命令日志中读取。因此,命令日志记录有着明显的不同。VoltDB使用命令日志记录来创建恢复点并确保耐久性,但它是实时写入主数据库存储器(RAM) - 伴随着所有相关的锁定问题等。

2
根据对Postgres的write ahead描述和您提到的VoltDB的命令日志,我看不出有什么区别。它们似乎是完全相同的概念,只是名称不同。
两者都仅将日志文件同步到磁盘,而不是数据,因此可以通过重放日志文件来恢复数据。
VoltDB的第10.4节解释了他们的社区版没有命令日志,因此无法通过ACID测试。即使在企业版中,我也看不到他们的事务隔离细节(例如PostgreSQL文档中的http://www.postgresql.org/docs/9.1/static/transaction-iso.html),这使我确信VoltDB与Postges一样认真。

0

这实际上只是一个粒度问题。他们在存储过程级别记录操作,大多数关系型数据库管理系统在单个语句(和更低级别)的级别记录日志。此外,他们关于优势的介绍有点误导:

与ARIES风格日志记录相比,命令日志记录的一个优点是可以在执行开始之前记录事务,而不是执行事务并等待日志数据刷新到磁盘。

他们也必须等待命令被记录,只是记录的记录要小得多。

如果我没记错,VoltDB的事务单位是存储过程。传统的关系型数据库管理系统通常需要支持包含任意数量语句的即席事务,因此存储过程级别的日志记录是不可能的。此外,在传统的关系型数据库管理系统中,存储过程通常并不真正确定(即给定参数+日志+数据总是产生相同的输出),而这对于此工作来说是必须的。

尽管如此,对于这种受限制的关系型数据库管理系统模型,性能改进将是巨大的。


0

我对此的理解如下(仅代表个人观点):

如此描述的命令日志仅记录事务发生的情况,而不记录其内部或外部发生的情况。好的,这里有一个神奇的部分...如果您想要回滚,则需要恢复最后一个快照,然后可以重放在此之后应用的所有事务(在上面的链接中描述)。因此,实际上您正在恢复备份并重新应用所有脚本,只是现在VoltDB已经为您自动化了。

我看到的真正区别是,您无法像普通事务日志(MSSQL、MySQL等)那样逻辑地回滚到某个时间点。普通事务日志可以轻松地回滚到某个时间点(在正确的设置中),因为事务可以“撤消”。

引起兴趣的问题出现了——参考pedz的帖子,即使使用命令日志,它是否始终能通过ACID测试?将会进行更多阅读...

补充:我读了更多的资料,我认为这对于非常大和繁忙的事务性数据库不是一个好主意。当命令日志填满时,会自动创建一个DB快照,以节省大量的事务日志和IO?你将在定期间隔内产生大量的IO量,并且还将使用您的内存到极限。此外,在我看来,您失去了轻松回滚到上一个自动快照之前某个时间点的能力 - 我认为这将变得非常棘手。

我宁愿坚持使用事务日志来处理事务系统。它已经被证明是有效的。


0
在我开始解释之前,先介绍一些术语:
日志方案:数据库使用诸如影子分页、预写式日志(WAL)等日志方案来实现并发性、隔离性和持久性(这是一个不同的话题)。
为了理解为什么WAL更好,让我们看一下影子分页存在的问题。在影子分页中,数据库使用主版本和数据库的影子版本,因此如果表大小为10亿,并且缓冲池管理器没有足够的内存来容纳所有元组(记录)在内存中,脏页不会被写入主版本,直到事务提交。

enter image description here

一旦所有交易都被提交,标志就会切换,影子版本就成为主版本。在上面的图表中,有Page 3和Page 5是旧的,可以进行垃圾回收。

  1. 这种方法的问题是留下了大量碎片化的元组,随机分布,与顺序访问脏页相比速度较慢,这就是Write Ahead Log所做的。

  2. 使用WAL的另一个优点是运行时性能(因为您不需要随机IO来刷新页面),但恢复时间较慢。而使用影子分页,恢复性能更快(偶尔需要)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接