公司博客上

潜入三角洲湖:打开事务日志

分享这篇文章

三角洲湖标志。
事务日志是理解Delta Lake的关键,因为它是贯穿其许多最重要特性的公共线程,包括ACID事务、可伸缩元数据处理、时间旅行等等。在本文中,我们将探讨Delta Lake事务日志是什么,它如何在文件级别上工作,以及它如何为多个并发读写问题提供一个优雅的解决方案。

什么是Delta Lake事务日志?

Delta Lake事务日志(也称为DeltaLog)是一个有序的记录,记录了Delta Lake表自创建以来所执行的每个事务。

事务日志的用途是什么?

真理的单一来源

Delta Lake构建在Apache Spark™之上,以便允许给定表的多个读取器和写入器同时在表上工作。为了在任何时候都向用户显示正确的数据视图,Delta Lake事务日志充当了一个真相来源单一-中央存储库,跟踪用户对表所做的所有更改。

当用户第一次读取Delta Lake表或在上次读取后修改过的打开表上运行新查询时,Spark检查事务日志,查看有哪些新事务发布到表中,然后用这些新更改更新最终用户的表。这确保了用户的表版本始终与最近查询的主记录同步,并且用户不能对表进行不同的、冲突的更改。

原子性在三角洲湖泊中的实施

ACID交易的四个属性之一,原子性,保证在您的数据库上执行操作(如INSERT或UPDATE)数据湖要么完全完成,要么根本不完成。如果没有这个属性,硬件故障或软件错误很容易导致只将部分数据写入表,从而导致混乱或损坏的数据。

事务日志是Delta Lake能够提供原子性保证的机制。无论如何,如果它没有记录在事务日志中,那么它就从未发生过。Delta Lake交易日志只记录完全执行的交易,并将该记录作为唯一的真实来源,允许用户对他们的数据进行推理,并对其基本的可信度放心,以拍字节的规模。

事务日志如何工作?

将事务分解为原子提交

每当用户执行修改表的操作(如INSERT、UPDATE或DELETE)时,Delta Lake将该操作分解为一系列由一个或多个类组成的离散步骤行动在下面。

  • 添加文件-添加数据文件。
  • 删除文件-删除数据文件。
  • 更新元数据-更新表的元数据(例如,改变表的名称,模式或分区)。
  • 设置事务-记录结构化流作业已经提交了一个具有给定ID的微批处理。
  • 变更协议-通过将Delta Lake事务日志切换到最新的软件协议来启用新功能。
  • 提交信息-包含关于提交的信息,包括执行了哪个操作,从哪里进行的,在什么时间进行的。

然后将这些操作按顺序记录在事务日志中,称为原子单元提交。

例如,假设用户创建了一个事务,向表中添加一个新列,并向其中添加一些数据。Delta Lake将该事务分解为其组成部分,一旦事务完成,将它们添加到事务日志中,如下所示:

  1. 更新元数据——将模式更改为包含新列
  2. 添加文件—用于添加的每个新文件

文件级别的Delta Lake事务日志

当用户创建Delta Lake表时,该表的事务日志将自动在_delta_log子目录。当他或她对该表进行更改时,这些更改将被记录为有序的原子提交到事务日志中。每次提交都被写入一个JSON文件,从000000. json.对表的其他更改将以升序数字生成后续JSON文件,以便将下一次提交写入000001. json,以下为000002. json等等。

Delta Lake事务日志文件结构图。

因此,作为一个例子,也许我们可以从数据文件向我们的表中添加额外的记录1.拼花而且2.拼花.该事务将自动添加到事务日志中,并作为提交保存到磁盘000000. json.然后,我们可能会改变主意,决定删除这些文件并添加一个新文件(3.拼花).这些操作将被记录为事务日志中的下一次提交,例如000001. json,如下图所示。

说明对同一文件执行操作的两次提交的图表。

尽管1.拼花而且2.拼花不再是Delta Lake表的一部分,它们的添加和删除仍然记录在事务日志中,因为这些操作是在我们的表上执行的——尽管事实上它们最终相互抵消了。Delta Lake仍然保留了这样的原子提交,以确保在我们需要审计表或使用“时间旅行”来查看表在给定时间点的情况时,我们可以准确地执行这些操作。

此外,Spark不会立即从磁盘中删除文件,即使我们从表中删除了底层数据文件。用户可以使用删除不再需要的文件真空

使用检查点文件快速重新计算状态

一旦我们总共向事务日志提交了10次,Delta Lake将以Parquet格式保存检查点文件_delta_log子目录。Delta Lake每10次提交自动生成检查点文件。

说明Delta Lake事务日志文件结构(包括分区目录)的图表。

这些检查点文件在某个时间点保存了表的整个状态——以本机Parquet格式保存,Spark可以快速方便地读取。换句话说,它们为Spark阅读器提供了一种完全再现表状态的“快捷方式”,使Spark避免重新处理成千上万个低效的小JSON文件。

为了加快速度,Spark可以运行一个listFrom操作查看事务日志中的所有文件,快速跳转到最新的检查点文件,并且只处理自最近的检查点文件保存以来所做的JSON提交。

为了演示这是如何工作的,假设我们一直在创建提交000007. json如下图所示。Spark通过这个提交来加快速度,自动将表的最新版本缓存在内存中。不过,与此同时,其他几个写入者(可能是您过于急切的队友)已经向表写入了新数据,并一直添加提交0000012. json

为了合并这些新的事务并更新表的状态,Spark将运行一个listFrom版本7操作查看表的新更改。

说明Spark如何读取最近的检查点文件以快速计算表状态的图表。

Spark不需要处理所有的中间JSON文件,而是可以直接跳到最近的检查点文件,因为它包含了提交#10时表的整个状态。现在,Spark只需要执行增量处理0000011. json而且0000012. json获取表的当前状态。然后Spark将该表的版本12缓存到内存中。通过遵循这个工作流,Delta Lake能够使用Spark以一种有效的方式随时更新表的状态。

处理多个并发读写

现在我们已经了解了Delta Lake事务日志在较高的级别上是如何工作的,接下来让我们讨论并发性。到目前为止,我们的示例主要涉及用户线性提交事务的场景,或者至少没有冲突。但是当Delta Lake处理多个并发读写时会发生什么呢?

答案很简单。由于Delta Lake是由Apache Spark提供支持的,因此多个用户不仅可以同时修改一个表——这是预期的。为了应对这些情况,Delta Lake雇佣了乐观并发控制。

什么是乐观并发控制?

乐观并发控制是一种处理并发事务的方法,它假定不同用户对表所做的事务(更改)可以在不相互冲突的情况下完成。它的速度之快令人难以置信,因为在处理pb级的数据时,用户很可能会同时处理数据的不同部分,从而允许他们同时完成不冲突的事务。

例如,想象一下你和我一起玩拼图游戏。只要我们都在做不同的部分——比如,你在角落,我在边缘——我们没有理由不能同时做更大的谜题中我们各自的部分,这样就能以两倍的速度完成谜题。只有当我们同时需要同样的东西时,才会有冲突。这就是乐观并发控制。

当然,即使使用乐观并发控制,有时用户也会尝试同时修改数据的相同部分。幸运的是,三角洲湖对此有协议。

乐观地解决冲突

为了提供ACID事务,Delta Lake有一个协议来确定提交应该如何排序(称为的概念)可串行性在数据库中),并确定在同时进行两次或两次以上提交的情况下该做什么。Delta Lake通过执行规则来处理这些情况互斥,然后尝试乐观地解决任何冲突。该协议允许Delta Lake按照ACID原则交付隔离,这确保在多个并发写入之后,表的结果状态与这些写入是连续发生的相同,并且彼此隔离。

一般来说,这个过程是这样进行的:

  1. 记录起跑表版本。
  2. 读/写记录。
  3. 尝试提交。
  4. 如果别人赢了,检查一下你读到的内容是否有所改变。
  5. 重复。

为了了解这一切是如何实时发生的,让我们看看下面的图表,看看当冲突突然出现时Delta Lake是如何处理冲突的。想象一下,两个用户从同一个表中读取数据,然后各自尝试向表中添加一些数据。

通过显示两个提交冲突的用户来说明乐观并发控制。

  • Delta Lake记录在进行任何更改之前读取的表的起始表版本(版本0)。
  • 用户1和用户2都试图同时向表中添加一些数据。在这里,我们遇到了冲突,因为下一个提交只能被记录为000001. json
  • Delta Lake用“互斥”的概念处理这种冲突,这意味着只有一个用户可以成功提交000001. json.用户1的提交被接受,用户2的提交被拒绝。
  • Delta Lake倾向于处理这种冲突,而不是为用户2抛出错误乐观地.它检查是否对表进行了新的提交,并无声地更新表以反映这些更改,然后简单地在新更新的表上重试用户2的提交(不进行任何数据处理),并成功提交000002. json

在大多数情况下,这种和解都是悄无声息地、无缝地、成功地进行的。但是,如果出现了Delta Lake无法乐观解决的不可调和问题(例如,如果用户1删除了用户2也删除了的文件),那么唯一的选择就是抛出一个错误。

最后需要注意的是,由于Delta Lake表上的所有事务都直接存储到磁盘上,因此该过程满足的ACID属性耐用性,这意味着即使在系统故障的情况下,它也会持续存在。

其他用例

时间旅行

每个表都是Delta Lake事务日志中记录的所有提交的总和——不多也不少。事务日志提供了一步一步的指导指南,详细说明了如何从表的原始状态转换到当前状态。

因此,我们可以通过从原始表开始,在任何时间点重新创建表的状态,并且只处理在该时间点之前的提交。这种强大的能力被称为“时间旅行”或数据版本控制,在任何情况下都可以成为救星。要了解更多信息,请阅读博客文章大规模数据湖的Delta时间旅行介绍,或参考三角洲湖时间旅行文件

数据沿袭和调试

Delta Lake事务日志作为对表进行的每一次更改的最终记录,为用户提供了可验证的数据沿袭,这对于治理、审计和遵从性目的非常有用。它还可以用于跟踪管道中无意的更改或错误的起源,追溯到导致它的确切操作。用户可以运行描述历史查看所做更改的元数据。

Delta Lake交易日志摘要

在这篇博客中,我们深入研究了Delta Lake事务日志如何工作的细节,包括:

  • 事务日志是什么,它是如何结构的,以及提交是如何作为文件存储在磁盘上的。
  • 事务日志如何作为真实的单一来源,从而允许Delta Lake实现原子性原则。
  • Delta Lake如何计算每个表的状态——包括它如何使用事务日志来从最近的检查点跟上进度。
  • 使用乐观并发控制允许在表发生变化时进行多个并发读写。
  • Delta Lake如何使用互斥来确保正确序列化提交,以及在发生冲突时如何无声地重试它们。
对开源的Delta Lake感兴趣?bob下载地址
参观三角洲湖在线中心要了解BOB低频彩更多,请下载最新代码并加入Delta Lake社区。

相关的

本系列文章:
潜入三角洲湖#1:解压事务日志
潜入三角洲湖#2:模式实施与演进
潜入三角洲湖#3:DML内部(更新,删除,合并)

相关文章:
什么是数据湖?
Delta Lake生产机器学习

免费试用Databricks

相关的帖子

看到所有公司博客上的帖子