GAE数据存储争用问题



我们的GAE应用程序在NDB中制作另一个网站关系数据库的本地副本。有4种实体类型-用户、表、行、字段。每个用户有一堆表,每个表有一堆行,每行有一堆字段。

SomeUser>SomeTable>ARow>A字段

因此,每个用户成为一个实体组。我需要一个可以为某个用户清除所有表(及其行)的功能。删除所有表和所有行的正确方法是什么,同时避免每秒5次操作的争用限制。

由于实体组上存在争用,当前代码正在获取TransactionFailedError s。(我忽略的细节是,我们只想删除属性"service"设置为某个值的表)

def delete_tables_for_service(user, service):
    tables = Tables.query(Tables.service == service, ancestor=user.key).fetch(keys_only=True)
    for table in tables:
        keys = []
        keys += Fields.query(ancestor=table).fetch(keys_only=True)
        keys += TableRows.query(ancestor=table).fetch(keys_only=True)
        keys.append(table)
        ndb.delete_multi(keys)

如果要删除的所有实体都在一个实体组中,请尝试在一个事务中全部删除它们。如果没有显式事务,每次删除都发生在自己的事务中,所有事务都必须排队(通过争用和重试)才能更改实体组。

您确定它是基于争用的,还是因为上面的代码是在事务中执行的?快速解决方法可能是增加重试次数,并为此方法启用跨组事务:

@ndb.transactional(retries=5, xg=True)

你可以在这里阅读更多信息:https://developers.google.com/appengine/docs/python/ndb/transactions.如果这不是罪魁祸首,可以考虑推迟或异步运行删除,以便它们随着时间的推移以较小的批量执行。NDB的诀窍是定期进行小批量的工作,而不是不频繁地进行大量的工作。以下是将代码转换为异步工作单元的一种方法:

def delete_tables_for_service(user, service):
    tables = Tables.query(Tables.service == service, ancestor=user.key).fetch(keys_only=True)
    for table in tables:
        # Delete fields
        fields_keys = Fields.query(ancestor=table).fetch(keys_only=True)
        ndb.delete_multi_async(fields_keys)
        # Delete table rows
        table_rows_keys = TableRows.query(ancestor=table).fetch(keys_only=True)
        ndb.delete_multi_async(table_rows_keys)
        # Finally delete table itself
        ndb.delete_async(table.key)

如果您想对删除、重试和失败进行更多控制,可以使用任务队列,也可以简单地使用延迟库(https://developers.google.com/appengine/articles/deferred):

  1. 在你的app.yaml中打开延迟
  2. 将对ndb.delete_multi的调用更改为deferred:

    def delete_tables_for_service(user, service):
        tables = Tables.query(Tables.service == service, ancestor=user.key).fetch(keys_only=True)
        for table in tables:
            keys = []
            keys += Fields.query(ancestor=table).fetch(keys_only=True)
            keys += TableRows.query(ancestor=table).fetch(keys_only=True)
            keys.append(table) 
            deferred.defer(_deferred_delete_tables_for_keys, keys)
    def _deferred_delete_tables_for_keys(keys):
        ndb.delete_multi(keys)
    

相关内容

  • 没有找到相关文章

最新更新