我们正在寻找构建一个具有需要相互排斥的代码区域的系统.在单个服务器上的专用托管环境中,我们可能会使用这个在多个线程上运行的简单代码:
SomeAsyncOperation(); lock(locker) { SomeSyncOperation1(); SomeSyncOperation2(); }
这是否可以在云中工作(假设webjobs可以跨多个物理机器运行)?特别是Azure.如果没有,将如何实施?到目前为止,我已经看过CloudBlockBlob和竞争对手的消费模式.人们为实现这一目标做了什么?
提前致谢.
编辑:更多信息
Operation1对表执行查找,然后如果Operation1什么都没找到,则Operation2向队列和表添加一个条目(否则抛出异常).为了防止将重复项添加到队列中,重要的是Operation1和Operation2以原子方式跨所有线程运行(应用程序使用async/await运行).
以下场景是竞争条件如何出现的示例:
T1 T2 O1() O1() O2() O2()
在线程T1上,operation1未找到重复项.线程T2出现并添加一个副本.威胁T1然后运行operation2,它不应该这样做.
通常可以使用lock()来防止这种情况,但我不认为这可以跨物理机器(例如在云中)工作.除非我对此错了......
在Azure的WebJobs SDK有一个声明SingletonAttribute
,可以应用到工作职能,以确保只有功能的单一实例在任何特定时间运行,甚至可以跨多个向外扩展实例.在幕后,它通过Azure Blob Leases进行分布式锁定.有关Singleton的更多信息,请访问wiki.这是一个示例函数(完整样本可以在样本repo中找到):
[Singleton] public static async Task ProcessWorkItem([QueueTrigger("workitems")] WorkItem workItem) { // Do your work - lock is maintained until this function completes }
只要将新队列消息写入队列,就会触发此函数workitems
.在函数开始执行之前,为函数获取分布式锁(blob lease),并保持该函数完成.如果同时触发该函数的另一个实例,则该实例将轮询锁定并在锁定释放后开始.
您可以使用Singleton的其他选项,包括更细粒度的锁定范围.例如,如果WorkItem
类型包含Region
属性,[Singleton("{Region}")]
则会在运行时自动绑定到该值,因此只会序列化同一区域中项目的函数实例.您还可以锁定不同的函数,这将允许您使用相同的Singleton范围注释两个不同的函数,因此两个函数的实例共享相同的锁.
当然,与进程线程同步一样,您必须考虑系统中的锁争用程度以及相应的设计.