Azure 表存储数据一致性
假设我在 Azure 表存储中有一个表
public class MyTable
{
public string PK {get; set;}
public string RowPK {get; set;}
public double Amount {get; set;}
}
,在 Azure 队列中有一条消息,其中显示添加 10 到金额。
现在假设一个工作角色
- 从队列中获取此消息
- 从表中获取行
- 金额+ = 10
- 更新表中的行
- 并且失败
一段时间后,消息再次在队列中可用。因此,下一个辅助角色:
- 从队列中获取此消息
- 从表中获取行
- Amount += 10
- 更新表中的行
- 从队列中删除消息
这些操作会导致 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
- Takes this message from queue
- Takes row from table
- Amount += 10
- Updates Row in Table
- And Fails
After a while message is available in queue again. So next worker role:
- Takes this message from queue
- Takes row from table
- Amount += 10
- Updates Row in Table
- Removes message from queue
Those actions results in Amount += 20
instead of Amount += 10
.
How can I avoid such situations?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我建议您实现一种乐观并发。您发送的用于更新行的消息应包含 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.
您放入队列中的所有消息都必须是幂等的。工作者角色总是有可能无法完成其工作,因此消息必须是可重复的。
因此,不要将 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.
你实现了这个还是上面的代码行只是一些想法?
“金额”意味着您正在考虑某种银行交易场景。直接使用 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?
批处理操作将以原子方式执行。
这是完全幂等的,您可以根据需要扩展工作者角色。此外,您不依赖于队列中的消息顺序,这不能保证 FIFO。
Batch operation will be executed atomically.
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.