锁定服务总线队列并防止其他人访问它

Lock a Service-Bus Queue and prevent others from accessing it

我有多个队列,多个客户端向其中插入消息。

在服务器端,我有多个微服务可以访问队列并处理这些消息。我想在服务正在处理队列时锁定队列,以便其他服务无法处理该队列。

意味着如果服务 A 正在处理来自队列 X 的消息,则在服务 A 完成消息处理之前,其他服务无法处理来自该队列的消息。其他服务可以处理来自除 X 以外的任何队列的消息。

有没有人知道如何锁定队列并防止其他人访问它?最好是其他服务会收到异常或其他内容,以便它们会在不同的队列上重试。

更新

另一种方法是将队列分配给服务,只要服务正在队列上工作,就不应将其他服务分配给队列,直到处理完工作项。这也是来之不易的事情。

Azure Service Bus 是具有竞争消费者的代理。您无法通过所有服务实例都在使用的通用队列获得您所要求的内容。

将工作项放入关系数据库。您仍然可以使用队列将工作推送给工作人员,但队列项现在可以为空。当工人收到他知道要查看数据库的项目时。忽略邮件内容。

这样消息是独立和幂等的。为了使队列工作,这两个属性通常必须保持。

这样您就可以更轻松地对实际上是连续的操作进行排序。您也可以使用事务。

也许您根本不需要排队。也许有固定数量的工人轮询数据库工作就足够了。但是,这会失去队列的自动缩放。

解决方案是使用 Azure 的 redis 将锁存储在内存中,并拥有使用 redis 存储管理这些锁的微服务。

lock()unlock() 操作是原子操作,锁有一个 TTL,因此队列不会被无限期地锁定。

有几种内置的方法可以做到这一点。如果你只有一个工人,你可以设置MessageOptions.MaxConcurrentCalls = 1

如果有多个,可以使用Singleton属性。这使您可以选择将其设置为侦听器模式或功能模式。前者提供您要求的行为,一个串行处理的 FIFO 队列。后者让您可以更细粒度地锁定,因此您可以专门锁定关键部分,确保一致性,同时允许更大的吞吐量,但不一定保留 order.

我的猜测 是他们已经实现了与您的 Redis 方法类似的单例属性,因此性能应该是等效的。不过我还没有对此进行测试。

您可以使用 Azure Service Bus message sessions

来实现

您队列中的所有邮件都必须使用相同的 SessionId 标记。在这种情况下,当客户端收到一条消息时,它不仅会锁定这条消息,还会锁定具有相同 SessionId(实际上是整个队列)的所有消息。