【问题标题】:Conflict accessing twice in azure storage table simultaneously在 Azure 存储表中同时访问两次冲突
【发布时间】:2019-06-23 02:09:31
【问题描述】:

我一直在运行一个脚本来从 Azure 存储表中检索数据(例如 this 一个作为参考)并将其从同一个存储帐户复制到另一个表中而没有问题。

现在,当我尝试访问后一个表以运行一些计算并将其从同一存储帐户复制到另一个表中时,问题就出现了。此脚本返回以下错误:

AzureConflictHttpError: Conflict
{"odata.error":{"code":"EntityAlreadyExists","message":{"lang":"en-US","value":"The specified entity already exists.\nRequestId:57d9b721-6002-012d-3d0c-b88bef000000\nTime:2019-01-29T19:55:53.5984026Z"}}}

然而,与此同时,我之前运行的代码也停止打印相同的错误,即使没有代码运行也不会重新开始,一遍又一遍地返回之前的错误。

有什么方法可以多次访问 Azure 存储中的同一个 API?

更新

添加源代码,抱歉之前没有这样做。基本上我并行运行的两个代码是相同的,但过滤器不同;在这个我正在从表 1 中获取数据(每秒有一行),我正在平均每分钟将这些数字添加到表 2 中,在另一个脚本上我正在从这个表中获取数据2 将这些行每分钟平均到另一个表 3 中的 5 分钟平均行,所以基本上有一些参数改变但代码基本相同。

会有第三个脚本,与这两个略有不同,但会以表 2 作为输入源,运行其他计算并将结果粘贴到未来表 4 中每分钟一个新的行中,所以总的来说我的想法是同时对多个表有多个条目以构建新的特定表。

import datetime
import time
from azure.storage.table import TableService, Entity

delta_time = '00:01:00'
retrieve_time = '00:10:00'
start_time = '08:02:00'
utc_diff = 3

table_service = TableService(account_name='xxx', account_key='yyy')

while True:
    now_time = datetime.datetime.now().strftime("%H:%M:%S") 
    now_date = datetime.datetime.now().strftime("%d-%m-%Y")
    hour = datetime.datetime.now().hour

    if hour >= 21:
        now_date = (datetime.datetime.now() + datetime.timedelta(days=1)).strftime("%d-%m-%Y")

    retrieve_max = (datetime.datetime.now() + datetime.timedelta(hours=utc_diff)+ datetime.timedelta(minutes=-10)).strftime("%H:%M:%S")

    start_diff = datetime.datetime.strptime(now_time, '%H:%M:%S') - datetime.datetime.strptime(start_time, '%H:%M:%S') + datetime.timedelta(hours=utc_diff)
    if start_diff.total_seconds() > 0:

        query = "PartitionKey eq '"+str(now_date)+"' and RowKey ge '"+str(retrieve_max)+"'"
        tasks=table_service.query_entities('Table1',query)
        iqf_0 = []

        for task in tasks:
            if task.Name == "IQF_0":
                iqf_0.append([task.RowKey, task.Area])  

        last_time = iqf_0[len(iqf_0)-1][0]
        time_max = datetime.datetime.strptime(last_time, '%H:%M:%S') - datetime.datetime.strptime(delta_time, '%H:%M:%S') #+ datetime.timedelta(hours=utc_diff)
        area = 0.0
        count = 0
        for i in range(len(iqf_0)-1, -1, -1):
            diff = datetime.datetime.strptime(last_time, '%H:%M:%S') - datetime.datetime.strptime(iqf_0[i][0], '%H:%M:%S')
            if diff.total_seconds() < 60:
                area += iqf_0[i][1]
                count += 1
            else: 
                break
        area_average = area/count

        output_row = Entity()
        output_row.PartitionKey = now_date
        output_row.RowKey = last_time
        output_row.Name = task.Name
        output_row.Area = area_average
        table_service.insert_entity('Table2', output_row)

        date_max = datetime.datetime.now() + datetime.timedelta(days=-1)
        date_max = date_max.strftime("%d-%m-%Y")
        query = "PartitionKey eq '"+str(date_max)+"' and RowKey ge '"+str(retrieve_max)+"'"
        tasks=table_service.query_entities('Table2',query)

        for task in tasks:
            diff = datetime.datetime.strptime(now_time, '%H:%M:%S') - datetime.datetime.strptime(task.RowKey, '%H:%M:%S') + datetime.timedelta(hours=utc_diff)
            print(i, datetime.datetime.strptime(now_time, '%H:%M:%S'), datetime.datetime.strptime(task.RowKey, '%H:%M:%S'), diff.total_seconds())
            if task.PartitionKey == date_max and diff.total_seconds()>0:
                table_service.delete_entity('Table2', task.PartitionKey, task.RowKey)

        time.sleep(60 - time.time() % 60)

【问题讨论】:

  • 您能否分享您的场景的更多细节?例如,您是否从 2 个应用程序访问 3 个表?您的应用程序如何读写这 3 个表(尤其是分区键和行键是如何组织的)?如果可能,您能否分享您的源代码,以便我们更好地理解您的问题?
  • 嗨@ZhaoxingLu-Microsoft,刚刚添加了代码和更多详细信息。 PartitionKey 基本上是“dd-mm-yyyy”格式的日子,而 RowKeys 是“hh:mm:ss”格式的小时。我的意图是减少从表1到表2的行数(从T1平均60行到T2中的1行),以及从表2到表3的相同操作(从T2平均5行到T3中的1行) .
  • 我没有仔细阅读代码,因为时间转换逻辑相当复杂且难以理解。您是否尝试过单独运行第一个脚本并查看错误是否仍然会发生?我怀疑单个脚本中的 while 循环导致了 EntityAlreadyExists 错误,因为循环插入具有相同 partition keyrow key 的实体不止一次.我建议您在将实体插入表之前编写一个日志以显示 分区键行键,这可能会帮助您找到罪魁祸首。
  • 我再次运行了第一个代码并且工作正常,可能由于缓存了一些信息,在冲突后它无法正常工作。所以你是说不能在同一个帐户的不同表中复制相同的分区键和行键?我会获取日志并更新帖子,谢谢!
  • 不,同一个分区键和行键不能在同一张表中重复,但是跨表就可以了。但是,由于您看到 EntityAlreadyExists 错误,这意味着您的代码确实尝试将具有相同分区键和行键的实体插入到同一个表中。

标签: python azure azure-storage


【解决方案1】:

听起来您正在运行两个代码来同时将同一 Azure 存储帐户中的数据从表 1 复制到表 2 到表 3。根据我的经验,这个问题通常是由于同时写入一条数据记录(一个表实体),或者对现有实体使用了不正确的方法,这是写入的资源竞争问题。

这是一个常见的表服务错误,您可以在here 找到它。

还有一个文档Inserting and Updating Entities解释了函数Insert EntityUpdate EntityMerge EntityInsert Or Merge EntityInsert Or Replace Entity之间的操作效果差异。

现在,您的代码没有为我们共享。考虑到所有可能的情况,有三种解决方案可以解决此问题。

  1. 依次运行两个代码,以便在不同表之间复制数据,而不是同时运行。

  2. 使用正确的函数更新现有实体的数据,可以参考上面的文档和类似的SO线程Add or replace entity in Azure Table Storage

  3. 对表实体的唯一主键使用全局锁,避免同时在两个代码中同时操作同一个表实体。

【讨论】:

  • 感谢@Peter Pan 的帮助,刚刚添加了代码和更多的 cmets,但基本上我的问题是您在第一行中提到的内容(我使用的是相同的表实体)。那么这应该是表实体的更新吗?但是如何,因为我分别每 1 分钟和 5 分钟添加更多新行?关于您的解决方案,第一个是不可能的,因为我是让这些脚本永久运行以在旅途中构建这些表,我将对后两个进行一些研究。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-12
  • 1970-01-01
  • 1970-01-01
  • 2018-07-31
  • 1970-01-01
  • 2020-03-21
  • 2015-07-31
相关资源
最近更新 更多