亚马逊QLDB并发模型 - 亚马逊 Quantum Ledger 数据库(亚马逊QLDB)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

亚马逊QLDB并发模型

重要

终止支持通知:现有客户可以在2025年7月31日终止支持QLDB之前使用亚马逊。有关更多详细信息,请参阅将亚马逊QLDB账本迁移到亚马逊 Aurora Postgr SQL e。

QLDBAmazon 旨在满足高性能在线事务处理 (OLTP) 工作负载的需求。QLDB支持SQL类似的查询功能,并提供完整ACID的事务。此外,QLDB数据项就是文档,可提供架构灵活性和直观的数据建模。QLDB以日记为核心,您可以使用访问数据所有更改的完整且可验证的历史记录,并根据需要将连贯的交易流式传输到其他数据服务。

乐观并发控制

在中QLDB,并发控制是使用乐观并发控制 () OCC 实现的。OCC其运作原则是,多笔交易可以在不相互干扰的情况下经常完成。

使用OCC,中的事务QLDB不会获取数据库资源的锁,并且在完全可序列化的隔离下运行。QLDB以串行方式运行并发事务,因此它产生的效果与这些事务按顺序启动的效果相同。

在提交之前,每个事务都会执行验证检查,以确保没有其他已提交的事务修改其正在访问的数据。如果此检查发现冲突的修改,或者数据的状态发生更改,则提交事务将被拒绝。但是,事务处理可以重新启动。

当事务写入时QLDB,OCC模型的验证检查由QLDB自己实现。如果由于的验证阶段失败而无法将交易写入日志OCC,QLDB则OccConflictException将返回到应用层。应用软件负责确保事务重新启动。应用程序应中止被拒绝的事务,然后从头开始重试整个事务。

要了解QLDB驱动程序如何处理和重试OCC冲突和其他临时异常,请参阅在 Amazon 中使用驱动程序了解重试政策 QLDB

使用索引避免全表扫描

在中QLDB,每个 PartiQL 语句(包括每个SELECT查询)都是在事务中处理的,并且受事务超时限制的约束。

按最佳实践标准,您应运行带有 WHERE 谓词子句的语句,该子句可以筛选索引字段或文档 ID。QLDB需要在索引字段上使用相运算符才能高效地查找文档;例如,WHERE indexedField = 123WHERE indexedField IN (456, 789)

如果没有这种索引查找,则QLDB需要在阅读文档时进行全表扫描。这可能会导致查询延迟和事务超时,还会增加与竞争交易发生OCC冲突的机会。

例如,假设一个名为 Vehicle 的表,该表仅在该 VIN 字段上有索引。它将包含以下文档。

VIN Make 模型 颜色
"1N4AL11D75C109151" "Audi" "A5" "Silver"
"KM8SRDHF6EU074761" "Tesla" "Model S" "Blue"
"3HGGK5G53FM761765" "Ducati" "Monster 1200" "Yellow"
"1HVBBAANXWH544237" "Ford" "F 150" "Black"
"1C4RJFAG0FC625797" "Mercedes" "CLK 350" "White"

两个名为 Alice 和 Bob 的并发用户正在使用分类账中的同一个表。以下两人想要更新两个不同的文档,如下所示。

Alice:

UPDATE Vehicle AS v SET v.Color = 'Blue' WHERE v.VIN = '1N4AL11D75C109151'

Bob:

UPDATE Vehicle AS v SET v.Color = 'Red' WHERE v.Make = 'Tesla' AND v.Model = 'Model S'

假设 Alice 和 Bob 同时开始事务。Alice 的 UPDATE 语句对 VIN 字段进行索引查找,因此它只需要读取那个文档即可。Alice 先完成并成功提交了她的事务。

Bob 的语句会筛选非索引字段,因此它会进行表扫描并遇到 OccConflictException。这是因为 Alice 提交的事务修改了 Bob 语句正在访问的数据,其中包括表中的每个文档,而非仅仅是 Bob 正在更新的文档。

插入OCC冲突

OCC冲突可能包括新插入的文档,而不仅仅是以前存在的文档。请考虑下图,其中两位用户(Alice 和 Bob)正在处理 表中的同一项目。他们都希望仅在谓词值尚不存在的情况下插入新文档。

Amazon QLDB 乐观并发控制 (OCC) 图显示了两个并发用户之间的冲突异常示例。

在此示例中,Alice 和 Bob 在单个事务中运行以下 SELECTINSERT 语句。只有当 INSERT 语句未返回任何结果时,他们的应用程序才会运行该 SELECT 语句。

SELECT * FROM Vehicle v WHERE v.VIN = 'ABCDE12345EXAMPLE'
INSERT INTO Vehicle VALUE { 'VIN' : 'ABCDE12345EXAMPLE', 'Type' : 'Wagon', 'Year' : 2019, 'Make' : 'Subaru', 'Model' : 'Outback', 'Color' : 'Gray' }

假设 Alice 和 Bob 同时开始事务。他们的两个 SELECT 查询都没有返回任何带有 ABCDE12345EXAMPLEVIN 的现有文档。因此,他们的应用程序继续执行 INSERT 语句。

Alice 先完成并成功提交了她的事务。然后,Bob 尝试提交他的交易,但QLDB拒绝了交易并抛出了。OccConflictException这是因为 Alice 提交的事务修改了 Bob 的SELECT查询结果集,并在提交 Bob 的事务之前OCC检测到了这种冲突。

此事务示例需要 SELECT 查询才能具有幂等。然后 Bob 可从一开始就重试整个事务。但是他的下一个 SELECT 查询将返回 Alice 插入的文档,因此 Bob 的应用程序将无法运行 INSERT

使事务幂等

上一节中的插入事务也是幂等事务的示例。换句话说,多次运行同一个事务会产生相同结果。如果 Bob 在不事先检查特定 INSERT 是否 VIN 存在的情况下运行,则该表最后可能会出现具有重复 VIN 值的文档。

除了OCC冲突之外,还要考虑其他重试场景。例如,有可能在服务器端QLDB成功提交事务,但客户端在等待响应时超时。作为最佳做法,我们建议将写事务设置为幂等,以避免在并发或重试时出现任何意想不到的副作用。

密文冲突 OCC

QLDB防止在同一日记块上同时编辑修订版。举一个例子,其中两个并发用户(Alice 和 Bob)想要编辑在分类账的同一个区块上提交的两个不同的文档修订版。首先,Alice 通过运行 REDACT_REVISION 存储过程请求编辑一个修订版,如下所示。

EXEC REDACT_REVISION `{strandId:"JdxjkR9bSYB5jMHWcI464T", sequenceNo:17}`, '5PLf9SXwndd63lPaSIa0O6', 'ADR2Ll1fGsU4Jr4EqTdnQF'

然后,当 Alice 的请求仍在处理,Bob 请求编辑另一个修订版,如下所示。

EXEC REDACT_REVISION `{strandId:"JdxjkR9bSYB5jMHWcI464T", sequenceNo:17}`, '8F0TPCmdNQ6JTRpiLj2TmW', '05K8zpGYWynDlEOK5afDRc'

QLDB拒绝了 Bob 的请求,OccConflictException尽管他们正在尝试编辑两个不同的文档修订版。这是因为 Bob 的修订版与 Alice 正编辑的修订版位于同一个区块上。Alice 的请求处理完毕后,Bob 可以重试他的编辑请求。

同样,如果两个并发事务尝试编辑同一修订版,则只能处理一个请求。在密文完成之前,另一个请求因OCC冲突异常而失败。之后,任何对同一修订版本进行编辑的请求都会导致错误,表明该修订已被编辑。

管理并发会话

如果您有使用关系数据库管理系统 (RDBMS) 的经验,则可能熟悉并发连接限制。QLDB与传统RDBMS连接的概念不同,因为事务是使用HTTP请求和响应消息运行的。

在中QLDB,类似的概念是一个活跃的会话。从概念上讲,会话类似于用户登录,它管理有关您对分类账的数据事务请求的信息。活动会话是指正在积极运行事务会话。它可以是最近完成事务的会话,服务预计它将立即启动另一笔事务。QLDB每个会话支持一个正在运行的事务。

每个分类账的并发活动会话限制在Amazon 中的配额和限制 QLDB中定义。达到此限制后,任何尝试启动事务的会话都会导致错误(LimitExceededException)。

有关会话生命周期以及QLDB驱动程序在运行数据事务时如何处理会话的信息,请参见驱动程序会话管理。有关使用QLDB驱动程序在应用程序中配置会话池的最佳实践,请参阅 Amazon QLDB 驱动程序建议配置 QldbDriver 对象中的。