Azure 表存储数据一致性

发布于 2024-08-12 11:57:40 字数 614 浏览 7 评论 0原文

假设我在 Azure 表存储中有一个表

public class MyTable
{
  public string PK {get; set;}
  public string RowPK {get; set;}

  public double Amount {get; set;}
}

,在 Azure 队列中有一条消息,其中显示添加 10 到金额

现在假设一个工作角色

  1. 从队列中获取此消息
  2. 从表中获取行
  3. 金额+ = 10
  4. 更新表中的行
  5. 并且失败

一段时间后,消息再次在队列中可用。因此,下一个辅助角色:

  1. 从队列中获取此消息
  2. 从表中获取行
  3. Amount += 10
  4. 更新表中的行
  5. 从队列中删除消息

这些操作会导致 Amount += 20 而不是金额 += 10

我怎样才能避免这种情况呢?

Let say I have Table in Azure Table Storage

public class MyTable
{
  public string PK {get; set;}
  public string RowPK {get; set;}

  public double Amount {get; set;}
}

And message in Azure Queue which says Add 10 to Amount.

Now let say one worker role

  1. Takes this message from queue
  2. Takes row from table
  3. Amount += 10
  4. Updates Row in Table
  5. And Fails

After a while message is available in queue again. So next worker role:

  1. Takes this message from queue
  2. Takes row from table
  3. Amount += 10
  4. Updates Row in Table
  5. Removes message from queue

Those actions results in Amount += 20 instead of Amount += 10.

How can I avoid such situations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

将军与妓 2024-08-19 11:57:40

我建议您实现一种乐观并发。您发送的用于更新行的消息应包含 amount 属性的“先前值”和“新值”。

因此,尝试更新行的第二个辅助角色将首先检查当前值是否仍等于“先前值”。如果不是,辅助角色知道出了问题,例如他可以直接取消消息而不进行更新。也许还会在某些日志中引发错误。

I would suggest that you implement a sort of optimistic concurrency. The message you send to update the row should contain both the "previous value" and the "new value" of the amount property.

So the second worker role that tries to update the row will first check that the current value is still equal to "previous value". If not the worker role knows something went wrong and he can for example just cancel the message without doing the update. And perhaps also raise an error in some log.

萧瑟寒风 2024-08-19 11:57:40

您放入队列中的所有消息都必须是幂等的。工作者角色总是有可能无法完成其工作,因此消息必须是可重复的。

因此,不要将 amount += 10 作为任务,而是执行 amount = 300 之类的操作。
获取 webrole 中的当前金额,添加 10,并将新金额放入队列中。

我不确定这是否是正确的方法。如果你这样做的话,如果两个网络角色尝试同时添加 10 就会出现问题。

All the messages that you put on the queue must be idempotent. There is always a chance a worker role won't finish his job so the message must be repeatable.

So instead of amount += 10 as a task do something like amount = 300.
Get the current amount in the webrole add 10 to it and place the new amount on the queue.

I'm not sure if this is the correct way. If you do it like this there will be a problem if two webroles try to add 10 at the same moment.

云朵有点甜 2024-08-19 11:57:40

你实现了这个还是上面的代码行只是一些想法?

“金额”意味着您正在考虑某种银行交易场景。直接使用 SQL Azure 可能会更好(因为您有 ACID 保证:http://blogs.msdn.com/ssds/archive/2009/03/12/9471765.aspx
“我们一直在服务中支持完整的 ACID 功能,并将继续这样做。”)

Afaik,我们可以说 windows azure 中的“表”类似于 google 的 bigtable,不是吗?

did you implemented this or are the lines of code up there just a few thoughts?

"amount" implies that you are thinking of some kind of bank transaction scenario. It would be probably better to work directly with SQL Azure (since you have ACID guarantees: http://blogs.msdn.com/ssds/archive/2009/03/12/9471765.aspx
„We have always supported full ACID capabilities in the service and will continue to do so.”)

Afaik, we can say that "tables" in windows azure are something like googles bigtable, aren't they?

筱果果 2024-08-19 11:57:40
  1. 队列中的消息有一个唯一的 MessageId。
  2. 辅助角色从队列中读取消息,从表中读取实体
  3. 更新金额字段
  4. 进行批量操作并将 2 行插入回表中。第一个是合并回表的更新实体,第二个是使用与行键相同的分区键和消息 ID 插入的实体。

批处理操作将以原子方式执行。

  1. 现在,在您的示例中,如果另一个辅助角色尝试第二次处理同一消息,则该操作将失败,因为该消息 ID 已存在于表中。然后,辅助角色应该从存储异常中捕获该状态代码并从队列中删除消息。

这是完全幂等的,您可以根据需要扩展工作者角色。此外,您不依赖于队列中的消息顺序,这不能保证 FIFO。

  1. Have a unique MessageId for your message in the Queue.
  2. Worker role reads the message from the queue, reads entity from the table
  3. Updates the Amount field
  4. Makes a Batch operation and inserts 2 rows back to the table. First one is the updated entity merged back to table and second one is an entity inserted with same Partition Key and Message Id as the row key.

Batch operation will be executed atomically.

  1. Now in your example, if another worker role tries to process the same message second time, that operation will fail because the message Id already exists in the table. Worker role then should catch that status code from storage exception and remove message from the queue.

This is fully idempotent and you can scale out worker roles as much as you want. Additionally you do not rely on message order in the queue which does not guarantee FIFO.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文