本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
亚马逊QLDB并发模型
重要
终止支持通知:现有客户可以在2025年7月31日终止支持QLDB之前使用亚马逊。有关更多详细信息,请参阅将亚马逊QLDB账本迁移到亚马逊 Aurora Postgr SQL
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 = 123
或WHERE 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)正在处理 表中的同一项目。他们都希望仅在谓词值尚不存在的情况下插入新文档。
在此示例中,Alice 和 Bob 在单个事务中运行以下 SELECT
和 INSERT
语句。只有当 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
查询都没有返回任何带有 ABCDE12345EXAMPLE
为 VIN
的现有文档。因此,他们的应用程序继续执行 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 对象中的。