【问题标题】:Odd Behavior of Azure Service Bus ReceiveBatch()Azure 服务总线 ReceiveBatch() 的奇怪行为
【发布时间】:2017-11-01 00:54:29
【问题描述】:

当前使用 Azure 服务总线主题并在使用 ReceiveBatch 方法接收我的消息时遇到问题。问题是预期的结果实际上并不是我得到的结果。这是基本的代码设置,用例如下:

    SubscriptionClient client = SubscriptionClient.CreateFromConnectionString(connectionString, convoTopic, subName);

    IEnumerable<BrokeredMessage> messageList = client.ReceiveBatch(100);
        foreach (BrokeredMessage message in messageList)
        {
            try
            {
                Console.WriteLine(message.GetBody<string>() + message.MessageId);

                message.Complete();
            }
            catch (Exception ex)
            {
                message.Abandon();
            }
        }

    client.Close();
    MessageBox.Show("Done");
  1. 使用上面的代码,如果我发送 4 条消息,则在第一次运行时轮询我得到第一条消息。在第二次运行时,我得到了另外 3 个。我希望同时得到所有 4 个。它似乎总是在第一次民意调查中返回一个奇异值,然后在随后的民意调查中返回。 (结果与 3 和 5 相同,第二次尝试发送 n 条消息中的 n-1 条,第一次尝试发送 1 条消息)。

  2. 如果我要接收 0 条消息,则该操作需要大约 30-60 秒才能获得 messageList(计数为 0)。我需要这个立即返回。

  3. 如果我将代码更改为 IEnumerable&lt;BrokeredMessage&gt; messageList = client.ReceiveBatch(100, new Timespan(0,0,0));,那么问题 #2 就会消失,因为问题 1 仍然存在,我必须调用两次代码才能获取所有消息。

我假设问题 #2 是因为我在 #3 中覆盖了默认超时值(尽管我发现如果有消息,它会立即响应而无需等待默认时间,这令人困惑)。但是,我不确定为什么我从未在单个 ReceiveBatch 中收到全部消息。

【问题讨论】:

  • 有问题的TopicPartitioned吗?我已经看到与 Partitioned Queue 完全相同的行为。
  • 谢谢,这是问题的一部分。

标签: c# azure azureservicebus


【解决方案1】:

让 ReceiveBatch() 正常工作的方法是做两件事。

  1. 在主题中禁用分区(我不得不为此创建一个新主题,因为创建后无法切换)
  2. 对每个创建的订阅启用批处理,如下所示:
  3. 列表项

SubscriptionDescription sd = new SubscriptionDescription(topicName, orgSubName); sd.EnableBatchedOperations = true;

完成这两件事后,我能够使用 IEnumerable&lt;BrokeredMessage&gt; messageList = client.ReceiveBatch(100, new TimeSpan(0,0,0)); 使主题按预期工作

【讨论】:

  • 禁用分区不是解决方案。我们需要能够可靠地接收分区队列中的所有消息。
【解决方案2】:

我在使用 ASB 队列时遇到了类似的问题。我发现我可以通过在接收批次之前增加客户端上的 PrefetchCount 来缓解它:

SubscriptionClient client = SubscriptionClient.CreateFromConnectionString(connectionString, convoTopic, subName);

client.PrefetchCount = 100;

IEnumerable<BrokeredMessage> messageList = client.ReceiveBatch(100);

来自 Azure 服务总线Best Practices for Performance Improvements Using Service Bus Brokered Messaging

预取使队列或订阅客户端能够在执行接收操作时从服务加载其他消息。

...

当使用 60 秒的默认锁到期时,一个很好的值 SubscriptionClient.PrefetchCount 是工厂所有接收器最大处理速率的 20 倍。例如,一个工厂创建了 3 个接收器,每个接收器每秒最多可以处理 10 条消息。预取计数不应超过 20*3*10 = 600。

...

预取消息增加了队列或订阅的整体吞吐量,因为它减少了消息操作或往返的总数。但是,获取第一条消息将花费更长的时间(由于消息大小增加)。接收预取消息会更快,因为这些消息已经被客户端下载。

【讨论】:

  • 这似乎有助于解决问题,但不能完全解决问题。感谢您的尝试。
【解决方案3】:

只是拼图的几块。即使在启用批处理和禁用分区之后,我仍然无法让它工作——我仍然需要进行两次 ReceiveBatch 调用。但是我确实找到了:

  • 重新启动 Service Bus 服务(我正在使用 Service Bus for Windows Server)为我解决了这个问题。
  • 执行单个 RecieveBatch 并且不执行任何操作(让消息锁过期)然后执行另一个 ReceiveBatch 会导致所有消息同时通过。 (对所有消息执行初始 ReceiveBatch 并调用 Abandon 不会导致该行为。)

所以它似乎是服务总线的内存缓存中的某种损坏/错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 2014-12-31
    • 2021-10-01
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多