1

我为将在多台服务器上运行的 .NET 应用程序获取了用于DistributedLock的 NuGet 包。对于那些不知道它利用SQL Server 的应用程序锁定功能来提供跨不同机器锁定的简单方法的人。我一直在使用它,因为它很好。但是,我想知道检查锁的顺序是否会导致释放锁时保持顺序。

例如...假设我的应用程序正在从队列中读取,然后按顺序处理每条消息。如果每条消息都是关于家庭的,我想按顺序处理家庭的每条消息怎么办。遇到的第一条消息可以使用 DistributedLock 的 Acquire 来检查帐户是否空闲,如果空闲则锁定它,然后开始处理该消息。然后假设队列侦听器应用程序正在另一台服务器上运行,它从同一家庭的队列中读取另一条消息。在这种情况下,Acquire 将等到家庭的锁空闲,然后重新锁定并处理消息。

var myLock = new SystemDistributedLock("UniqueHouseholdIdentifier");

using (myLock.Acquire())
{
    // message processed here in the lock
}

但是,如果有第三台机器运行相同的应用程序并且遇到具有相同家庭标识符的消息怎么办?

因此,机器#1 获取了家庭 ID A01 的第一条消息,将其锁定并开始处理它。机器#2 在队列中为 A01 抓取第二条消息并等待。机器#3 从队列中为 A01 抓取第三条消息并等待。

在上述情况下,当机器#1 完成处理它的 A01 的消息并释放锁时,机器#2,它为 A01 拾取第二条消息,在机器 #3 之前运行?或者它实际上是随机的,并且机器#2 或#3 可能会获得下一个锁?秩序会维持吗?

4

1 回答 1

1

我提出这个答案时需要注意的是,我是 DBA 而不是应用程序开发人员(我知道的 C# 足够危险)。

查看您链接到的两件事,我不认为该请求有任何顺序。sp_getapplock 使用的锁定功能与 SQL 用于锁定行和表等内容的锁定功能相同。只是您正在定义虚拟资源的名称。因此,当任务通过 sp_getapplock 请求锁定时,会发生以下情况(在高级别)

  • 任务进入可运行队列
  • 任务到达队列的顶部
  • 如果锁当前不被另一个进程拥有,你得到它,你就完成了
  • 如果锁当前由另一个进程拥有,则进入等待状态
  • 当锁被释放时,您的进程会收到“唤醒”信号,此时它会进入可运行队列(即返回第一步)

问题是每个调度程序都有自己的可运行队列(即每个 SQL 实例不只有一个可运行队列),因此哪个进程首先到达那里是不确定的。

如果您正在寻找订单处理,您可能需要查看 Service Broker 或其他一些具有主题和按订单交付的队列技术。

于 2016-06-09T20:18:34.543 回答