同一订阅者的 Azure 服务总线多个实例

Uma*_*air 1 azureservicebus azure-servicebus-topics asp.net-core

我有一种情况,我有一个 asp.net 核心应用程序,它在启动时将订阅客户端注册到一个主题 ( IHostedService),这个订阅客户端本质上有一个回调字典,每当它检测到一个主题中的新消息时,它就需要触发一个 id(这个 id 存储在消息属性中)。这本字典存在于应用程序的整个生命周期中,并且在内存中。

在 azure 上的 asp.net 核心应用程序服务的单个实例上一切正常,一旦我扩展到 2,我注意到有时订阅中的回调没有触发。这是有道理的,因为我们现在有两个实例,每个实例都有自己的回调字典存储。

所以我更新了代码来检查订阅的id是否存在,如果不存在,则放弃消息,如果存在,则获取回调并调用它。

public async Task HandleMessage(Microsoft.Azure.ServiceBus.Message message, CancellationToken cancellationToken)
{
    var queueItem = this.converter.DeserializeItem(message);

    var sessionId = // get the session id from the message
    if (string.IsNullOrEmpty(sessionId))
    {
         await this.subscriptionClient.AbandonAsync(message.SystemProperties.LockToken);
         return;
    }

    if (!this.subscriptions.TryGetValue(sessionId, out var subscription))
    {
        await this.subscriptionClient.AbandonAsync(message.SystemProperties.LockToken);
        return;
    }

    await subscription.Call(queueItem);

    // subscription was found and executed. Complete message
    await this.subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
}
Run Code Online (Sandbox Code Playgroud)

但是,问题仍然存在。我唯一的猜测是,在调用时AbandonAsync,同一个实例再次接收消息?

我想我真正想问的是,如果我有多个主题订阅客户端实例都指向该主题的同一个订阅者,是否所有实例都可以获得消息的副本?或者是不能保证的。

Sea*_*man 5

如果我有多个主题订阅客户端实例都指向该主题的同一个订阅者,是否所有实例都可以获得消息的副本?或者是不能保证的。

不。如果所有客户端都指向同一个订阅,则只有一个会收到该消息。

您遇到了与竞争消费者进行横向扩展的问题。如果您要向外扩展,您永远不知道哪个实例会选择消息。而且由于您的状态是本地的(在每个实例的内存中),这会不时失败。额外的缺点是成本。通过在“错误”实例上获取消息并放弃,您将在消息传递方面支付更高的成本。

为了解决这个问题,你要么需要一个共享的/集中的,要么围绕这个改变你的架构。