【问题标题】:Azure Table Update Concurrency IssueAzure 表更新并发问题
【发布时间】:2013-06-05 09:17:44
【问题描述】:

我正在尝试针对每笔交易更新用户信用/计数信息。如果我们每秒交易超过 2/4 次,则以下更新不会更新计数/用户信用信息。

基本上是两个问题。

  1. 有时更新未发生并显示 NO,错误消息。
  2. 更新失败并出现错误消息:412:失败:代码:412 值:前提条件失败详细信息(如果有):UpdateConditionNotSatisfied 未满足请求中指定的更新条件。 RequestId:1beb3fa9-9ad2-46f7-b8ee-af3a09300db7 时间:2013-06-09T16:12:17.6797130Z。

我正在使用 Azure 为 SMS API 制作从 RDMBS 迁移到 NoSQL 的原型。不知道为什么会发生这样的事情。

下面的代码粘贴

public function update_credit_to_azure_table () {
  // Create table REST proxy.
  $tableRestProxy = ServicesBuilder::getInstance()
    ->createTableService($this->connectionString);

  $result = $tableRestProxy->getEntity("tblapilogin",  $this->apiusr , $this->apiusr);
  $entity = $result->getEntity();

  $new_api_balance = $this->global_api_credit - $this->credittodeduct;
  $credit_used = $this->api_credit_used + $this->credittodeduct;

  $entity->setPropertyValue("global_api_credit", $new_api_balance); //Update Balance.
  $entity->setPropertyValue("api_credit_used", $credit_used); //credit used Updated .

  try {
    $tableRestProxy->updateEntity("tblapilogin", $entity);

    echo "<br>New Blance is: " . $new_api_balance;
    echo "<br>credit_used  is: " . $credit_used;
  }
  catch(ServiceException $e) {
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
  }
}

乐观并发的更新函数是这里的主要测试。

【问题讨论】:

  • 第一种应该基本不会发生。第二个是正常的,如果您正在尝试更新一个实体但它已经(同时)被另一个事务更新,那么 updateEntity 将失败,您将不得不重试。
  • 这就像每秒少于 10 个事务,即使第二个行为也不会发生。我相信 azure table storage 声称每秒有超过 400 个事务。 (不确定更新是否非常有限)。我听说 Etag 的东西在这里是相关的,如果需要控制,如何将它与 API 调用一起应用?
  • 我可能错了,因为我没有阅读限制,但我相信每秒 400 次是每个分区的批量更新,而不是单个实体上的单个更新。
  • 另外,this link 可能会有所帮助。
  • 我关闭了唠叨,但我没有看到性能有任何提高...我尝试每秒对同一实体进行少于 10 次更新。 (我在表中有一个实体,其行键和分区键为“as234q243”,它只是表中的一个实体,具有相同的行和分区键)并且性能如此糟糕。不确定表存储是否仅用于插入。

标签: azure azure-storage azure-blob-storage azure-table-storage


【解决方案1】:

我不是 PHP 专家,但查看Github 的源代码,我发现updateEntity 函数总是强制使用ETag,即该函数强制条件更新:

public function updateEntity($table, $entity, $options = null)
    {
        return $this->_putOrMergeEntityImpl(
            $table,
            $entity,
            Resources::HTTP_PUT,
            true, 
            $options
        );
    }

基于文档here

如果实体的 ETag 与更新时指定的不同 请求,更新操作失败,状态码为 412(前提条件 失败的)。此错误表明实体已在 服务器,因为它被检索。要解决此错误,请检索 再次实体并重新发出请求。

要强制进行无条件更新操作,请将 If-Match 请求头中的通配符 (*)。通过 该操作的值将覆盖默认乐观 并发并忽略 ETag 值中的任何不匹配。

如果 Etag 值不匹配,您将收到一个 412 错误。

我建议使用insertOrReplaceEntity 操作而不是updateEntity 操作,因为如果实体不存在,它将创建一个实体,否则它将更新它。又看代码,这个没有使用ETag

public function insertOrReplaceEntity($table, $entity, $options = null)
    {
        return $this->_putOrMergeEntityImpl(
            $table,
            $entity,
            Resources::HTTP_PUT,
            false, 
            $options
        );
    }

注意这两个函数中的第四个参数。这是强制使用 ETag 的原因。在updateEntity 中设置为true,而在insertOrReplaceEntity 中设置为false

【讨论】:

  • 非常感谢您的详细回复。乐观并发的更新功能是更新用户余额/信用/剩余资金的主要需求。我很震惊,无法确定出了什么问题,因为每秒更新 5 或 10 次点击不会像这样。
【解决方案2】:

这与史蒂夫在他的一集中解释的问题相同。

http://channel9.msdn.com/Shows/Cloud+Cover/Cloud-Cover-Episode-43-Scalable-Counters-with-Windows-Azure

如果您在同一实体上每秒执行 1 次读取、写入操作,它将在没有 Etag 失败的情况下工作。否则,您已经围绕此构建了自己的智能逻辑。

另一个有用的资源是:

How to build a highly scaleable global counter in Azure?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多