【发布时间】:2017-09-17 14:37:09
【问题描述】:
我正在再次调查TransactionFailedError (too much contention on these datastore entities... 意外发生的情况,其中代码仅读取因争用问题而受到指责的实体组。
设置
GAE 标准环境,带有 NDB 的 Python 2.7 (SDK 1.9.51)。我设法在一个隔离的应用程序(只有我作为用户)中观察到错误,其中相同的请求处理程序在任务队列中执行,并且对下面提到的实体组的读/写访问仅由该处理程序完成。
处理程序每秒执行几次,基本上是一个迁移/复制任务,将现有的OriginChild 实体从一个巨大的组中移动到单独的组中,作为新的Target 实体。这是每个OriginChild 实体的一项任务。
在一个跨组事务函数ndb.transaction(lambda: main_activity(), xg=True)内,每个请求处理程序...:
-
确实使用 get_async NDB 小任务来检索两个实体:
Key(OriginGroup, 1)(所有请求都一样)Key(OriginGroup, 1, OriginChild, Foo)(每个请求的唯一对象)
Key(TargetConfig, 1).get()有
Key(Target, Foo).get()(真的没有父母!)如果 Key 不存在,在事务函数离开之前,
Key(Target, Foo).put_async()和get_result()是否存在
所以,这些是事务中的只读实体:
Key(Origin, 1)Key(Origin, 1, OriginChild, Foo)Key(TargetConfig, 1)
代码不会进行任何更改,这些实体不会被删除或写回数据存储区。此外,没有其他正在运行的请求尝试写入这些实体组 - 这些组中几个月都没有写入操作)。
放入数据存储区的唯一实体是 Key(Target, Foo),其中 ID 对于每个请求都是唯一的。
错误
大约 60-70% 的请求将在没有错误的情况下运行。
当 TransactionFailedError 发生时,它将在事务函数内部,日志显示如下:
suspended generator get(context.py:758) raised TransactionFailedError(too much contention on these datastore entities. please try again. entity group key: app: "e~my-test-app"
name_space: "test"
path <
Element {
type: "OriginGroup"
id: 1
}
>
)
在大约 80% 的失败请求中,错误将与 Key(OriginGroup, 1) 相关(尽管整个组都是只读的)。
在大约 10% 的失败请求中,错误将显示 Key(TargetConfig, 1)(也是只读的)。
在剩下的约 10% 中,它将归咎于新实体,例如Key(Target, Foo),或者对于任何 TargetChild 的 ID,请求都会执行迁移,而且它似乎只发生在 put() 期间,而不是之前的 get() 尝试期间。
理论
我对事务和实体组的理解是,NDB 遵循乐观并发控制,因此来自同一实体组的大规模读取操作是可能的(因此可扩展性),并且由于技术原因仅用于事务性写入操作存在每个实体组每秒约 1 个写入操作的限制,并且每个事务不超过 25 个实体组。
但是,我的观察表明读取操作也可能导致too much contention 错误。但这个想法也让我感到困惑,因为如果你的目标是强一致性,它会使 GAE 与 Datastore 的可扩展性大大降低。所以也许这里还有其他事情发生。
我发现这个关于 SO 的评论声称我的假设是正确的:
"注意:如果与访问同一实体组的其他事务发生冲突,则 XG 事务中实体组的第一次读取可能会引发 TransactionFailedError 异常。这意味着即使仅执行读取的 XG 事务也可能会失败并发异常。”
来源:Contention problems in Google App Engine
我能够在新文档中找到引用,现在位于 Superseded Storage Solutions > DB Client Library for Cloud Datastore > Overview
问题
引用的语句是否仍然适用于 NDB(或仅适用于 DB 和/或版本冲突)?
如果是这样:建议使用哪种模式来避免跨实体组的事务性读取出现争用错误?
【问题讨论】:
标签: python-2.7 google-app-engine google-cloud-datastore app-engine-ndb google-app-engine-python