【发布时间】:2015-10-03 20:18:07
【问题描述】:
我在 Google App Engine 中遇到了争用问题,并尝试了解发生了什么。
我有一个带有注释的请求处理程序:
@ndb.transactional(xg=True, retries=5)
..在该代码中,我获取了一些内容,更新了其他一些内容等。但有时在请求期间日志中会出现类似这样的错误:
16:06:20.930 suspended generator _get_tasklet(context.py:329) raised TransactionFailedError(too much contention on these datastore entities. please try again. entity group key: app: "s~my-appname"
path <
Element {
type: "PlayerGameStates"
name: "hannes2"
}
>
)
16:06:20.930 suspended generator get(context.py:744) raised TransactionFailedError(too much contention on these datastore entities. please try again. entity group key: app: "s~my-appname"
path <
Element {
type: "PlayerGameStates"
name: "hannes2"
}
>
)
16:06:20.930 suspended generator get(context.py:744) raised TransactionFailedError(too much contention on these datastore entities. please try again. entity group key: app: "s~my-appname"
path <
Element {
type: "PlayerGameStates"
name: "hannes2"
}
>
)
16:06:20.936 suspended generator transaction(context.py:1004) raised TransactionFailedError(too much contention on these datastore entities. please try again. entity group key: app: "s~my-appname"
path <
Element {
type: "PlayerGameStates"
name: "hannes2"
}
>
)
.. 后跟堆栈跟踪。如果需要,我可以更新整个堆栈跟踪,但它有点长。
我不明白为什么会这样。查看我的代码中出现异常的行,我在一个完全不同的实体(Round)上运行get_by_id。错误消息中提到的“PlayerGameStates”,名称“hannes2”是另一个实体GameState的父级,之前几行已从数据库中get_async:ed;
# GameState is read by get_async
gamestate_future = GameState.get_by_id_async(id, ndb.Key('PlayerGameStates', player_key))
...
gamestate = gamestate_future.get_result()
...
奇怪(?)的事情是,该实体没有写入数据存储区。我的理解是,如果同一实体同时更新,可能会出现争用错误,并行..或者如果在短时间内发生太多写入..
但是在读取实体时也会发生这种情况吗? ("suspended generator get.."??) 而且,这是否发生在 5 次 ndb.transaction 重试之后..?我在日志中看不到任何表明已进行任何重试的内容。
非常感谢任何帮助。
【问题讨论】:
-
我会看看你的关键结构。争用不仅仅在实体层面。您还需要检查父母。查看您的实体组的范围,以便了解您为什么会出现争用。
-
谢谢。我试图让实体组保持较小,并避免争用——但我会进行更多研究。在这种情况下,在与父
ndb.Key("PlayerGameStates", "hannes2")的实体组中发生了争用,对吧?我仍然不明白为什么从中读取会触发异常/争用?我在哪里可以阅读更多关于此的信息..? -
@TimHoffman 好的,刚刚在Cross-group transactions documentation 下找到了这个:“注意:如果与访问该实体组的其他事务发生冲突,则在 XG 事务中第一次读取实体组可能会引发 TransactionFailedError 异常相同的实体组。这意味着即使是仅执行读取的 XG 事务也可能因并发异常而失败。"
-
尝试构建您的应用程序以使用任务队列(您可以将任务过渡到队列)来更新根实体和/或使用分片。在大多数情况下,可以有独立实体的解决方案并通过任务队列更新聚合/根/邻居。在修改数据之前不要开始事务。这是一个很好的模式先读取实体,检查它是否需要修改,如果是则启动事务。
标签: python google-app-engine google-cloud-datastore app-engine-ndb contention