【问题标题】:How to make blobstore delete operations transaction safe with ndb?如何使用 ndb 使 blobstore 删除操作事务安全?
【发布时间】:2013-07-14 08:04:54
【问题描述】:

如果我们在 appengine 上启动一个删除复杂对象的事务,并且该对象附加了一些需要删除的 blob 引用,那么我们就有问题了。如果我们只是删除 blob,则事务可能会失败,但 blob 会消失,因为 blobstore 是独立工作的(这与事务的想法背道而驰)。

现在我们有了这个很酷的新 NDB,它有一个上下文缓存,没有记录的 API(?)可以解决问题。

工具箱:

  • ndb.get_context()(未在 ndb 的函数参考中记录)
  • ndb_context.call_on_commit(delete_blobs_call_on_commit)

    def delete_blobs_call_on_commit():
       ndb_context = ndb.get_context()
       blobstore.delete(ndb_context.list_of_blobkeys_to_delete)
       # OR: taskqueue.add(url+ndb_context.list_of_blobkeys_to_delete)
    

任务:将事务期间要删除的 blobkey 附加到上下文对象,并在事务后将其删除。

更新:call_on_commit() 不允许数据库操作(可能包括 blobstore.delete,但尚未尝试过)并且会抛出 BadRequestError: Cannot start a new operation in a finished transaction,所以唯一的解决方案可能真的是任务队列。

更新:可以从使用 call_on_commit() 注册的函数调用带有 @ndb.non_transactional 装饰器的函数。因此,可以尝试在提交成功时删除 blob,并希望您没有会导致孤儿的异常。

问题:如何安全地使用上下文缓存?您是如何解决 blob 删除问题的?

【问题讨论】:

  • 这将如何解决问题?删除 blobkey 可能仍会失败,现在您有孤立 blobkey。考虑使用前滚事务模型,跟踪两个删除,在任务中运行它。然后,该任务可以确认它已删除所有内容,然后自行清理。如果它在任何时候失败,清扫器可以向前滚动并重试,直到所有实体都消失。只是一个建议。
  • 我考虑将所有 blob 删除推入任务队列并在事务失败时删除任务,但这很不方便。 delete_blobs_call_on_commit() 仍然可以使用任务队列而不是直接删除 blob,但我认为有一些孤儿是可以接受的。如果 blobstore 的成功率达到 99.9%,那就没问题了。这个问题主要涉及收集前滚数据。
  • 这篇文章你看过了吗,或许会给你一些想法blog.notdot.net/2009/9/Distributed-Transactions-on-App-Engine
  • 已加入书签,谢谢。
  • 如果您的安全删除所有 blob 的函数需要事务,则可以在使用 @ndb.transactional(xg=True, propagation=ndb.TransactionOptions.MANDATORY) 装饰它时从 call_on_commit 调用它。至少,到目前为止,这种方法在我的实验中是有效的。

标签: google-app-engine blobstore app-engine-ndb


【解决方案1】:

AFAIK blob 实际上在数据存储中具有表示形式,因此您可以在事务中使用它们。

要安全地使用上下文缓存,请使用带有这些标志的常规模型/密钥 get() 和 put() 操作:use_memcache=False、use_datastore=False、use_cache=True。您还可以将这些标志作为类变量放入模型定义中。

【讨论】:

  • 但是BlobInfo对象没有祖先,我的理解是没有祖先==没有事务。主要要解决的问题是在事务中删除一个blob,即使事务失败了也会删除这个blob。
  • 你可以使用 XP 交易吗?否则,您将被淹没,并且您将不得不忍受(非常)小概率泄漏 blob 密钥。
  • 不幸的是,我每组有超过 5 个 blob(跨组(Xg 限制为 5)。
  • 目前我接受泄漏一些blob的可能性,但不惜一切代价避免在事务提交前丢失blob,只有任务队列可以解决泄漏问题,因为它可以重试。
【解决方案2】:

使用 blob 无孤删除实体组的一种方法是在没有事务的情况下进行可重复的容错删除操作(幂等操作)。

  1. 将实体/祖先标记为已删除,放置(确保没有人可以再使用它很重要)
  2. 从叶子到父级删除没有事务
  3. 任何时候发生错误,中止
  4. 用户(看到已删除的项目)或系统(任务队列)可以稍后重试删除
  5. 删除必须能够跳过已删除的引用才能实现幂等

谁能看出这种方法存在问题?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多