【问题标题】:Azure Storage Table - Insert batch of row and check if they existsAzure 存储表 - 插入一批行并检查它们是否存在
【发布时间】:2017-04-02 15:39:20
【问题描述】:

我为某些服务发送查询并返回结果。我想知道我过去是否已经得到相同的“答案”。所以,我打算使用 Azure Table 作为缓存机制。

我做这个小 POC:

TableBatchOperation batchOperation = new TableBatchOperation();
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1");
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2");
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
table.ExecuteBatch(batchOperation);

当我第一次运行此代码时,它运行良好。最后,我在表中有 2 行。

问题出在第二次运行。当我执行这段代码时:

TableBatchOperation batchOperation = new TableBatchOperation();
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1");
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2");
CachedUrl customer3 = new CachedUrl(Guid.Empty, "test3");
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
batchOperation.Insert(customer3);
table.ExecuteBatch(batchOperation);

注意添加customer3

期望得到的是一条消息:

  • customer1 - 存在
  • customer2 - 存在
  • customer3 - 添加

我实际得到的是这个异常(在ExecuteBatch() 方法上):

请求信息RequestID:5116ee8a-0002-0024-7ac1-415787000000 请求日期:2016 年 11 月 18 日星期五 17:33:08 GMT 状态消息:0: 指定的实体已经存在。错误代码:EntityAlreadyExists

服务器发现 #1 实体存在,因此,跳过整个任务。

我怎样才能得到预期的答案?

天真的解决方案是尝试将所有 N 项逐个添加。但是这个解决方案是最慢的一个(N 个 HTTP 请求而不是 1 个请求)。

【问题讨论】:

    标签: c# azure azure-storage azure-table-storage


    【解决方案1】:

    这是预期的行为。一旦该批次中的任何实体失败,整个批次就会失败。

    您可以使用InsertOrReplace 方法而不是Insert。如果实体存在,这将更新实体,否则插入实体。

    来自documentation

    将 TableOperation 添加到插入 如果实体不存在,则将指定实体放入表中;如果 实体确实存在,然后它的内容被替换为提供的 实体。

    【讨论】:

    • 使用InsertOrReplace如何解决我的问题?这样,执行命令后,我无法知道这些项是新添加的还是刚刚替换的……
    • 我不相信有办法判断实体是被替换了还是只是被认证了。也许表存储不太适合您正在尝试做的事情。您是否考虑过其他选择?
    【解决方案2】:

    Azure 表存储批处理操作是原子的,因此预计会在第一次失败的操作时返回。一个批处理操作可能包含 1000 次操作,表服务在检测到第一次失败后继续执行所有操作的意义不大。

    存储异常返回批处理中失败操作的实际索引以及与之相关的错误。

    在下面的示例中,失败操作的索引为 0,错误为 EntityAlreadyExists:

    0:指定的实体已经存在。错误代码:EntityAlreadyExists

    您可以编写一个重试逻辑来捕获 StorageException,解析错误,如果错误是 EntityAlreadyExists,则从批处理中删除具有该索引的操作并重新提交批处理操作。

    请参阅我在 Nuget 中实现的 azure Storage Exception 解析器,它为您从 StorageException 对象中提取失败操作的索引和其他有用信息(如 HttpStatusCode):https://www.nuget.org/packages/AzureStorageExceptionParser/

    为了避免在每个失败的操作上多次来回调用 azure,您可以探索以下替代解决方案:

    每次将实体插入表时,您还会插入第二个具有相同分区键的实体,该分区键仅包含行键的一个属性。让我们将此第二个实体称为 RowKeyTracker 实体。它将与原始实体具有相同的分区键,以便您可以进行批处理操作。它将有一个唯一的行键,您将知道它以便对其进行查询,并且它将具有一个属性,即该分区的附加行键。如果 RowKeyTracker 实体已经存在,您只需在每次插入新实体时将新行键附加到该分区键的行键属性,反之亦然,当您删除实体时,您也可以继续从 RowKeyTracker 中删除该行键实体。

    因此,您可以使用此 Row Key 跟踪器实体来确定该分区的 Row 键是否已插入,方法是先查询它。

    您可以将此方法与第一种方法(重试)结合使用,以获得更强大的解决方案

    【讨论】:

    • 在 OP 的问题中,客户 id 是递增的,因此替代方法是为表中的每个分区(而不是第二个表)维护一个单独的计数行,并知道将哪些客户 id 插入到表中已经通过对计数行进行点查询。当然,如果客户 id 不是增量的,那么你不能使用这个捷径。
    • 文档说“一个批处理操作可能包含多达 100 个单独的表操作,并要求每个操作实体必须具有相同的分区键。”。希望它有助于决定 (docs.microsoft.com/en-us/dotnet/api/…)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 2011-02-08
    • 2019-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多