2

假设我在 Azure 表存储中有表

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

  public double Amount {get; set;}
}

Azure Queue 中的消息显示Add 10 to Amount

现在让我们说一个工人角色

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

一段时间后,消息再次在队列中可用。所以下一个工人角色:

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

这些动作导致Amount += 20而不是Amount += 10

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

4

4 回答 4

2

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

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

于 2009-12-11T12:38:28.347 回答
1

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

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

我不确定这是否是正确的方法。如果您这样做,如果两个 webrole 尝试同时添加 10,将会出现问题。

于 2009-11-24T15:35:51.957 回答
0

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

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

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

于 2010-04-09T17:40:56.540 回答
0
  1. 在队列中为您的消息提供一个唯一的 MessageId。
  2. Worker 角色从队列中读取消息,从表中读取实体
  3. 更新金额字段
  4. 进行批处理操作并将 2 行插入回表中。第一个是合并回表的更新实体,第二个是插入的实体,其分区键和消息 ID 与行键相同。

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

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

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

于 2016-02-07T02:08:04.243 回答