Amazon QLDB 并发模型 - Amazon Quantum Ledger Database (Amazon QLDB)

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

Amazon QLDB 并发模型

Amazon QLDB 旨在满足高性能联机事务处理 (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查询结果集,而 OCC 在提交 Bob 的事务之前就检测到了这种冲突。

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

使事务幂等

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

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

Redcation 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 对象