Azure 服务总线 ReceiveBatch() 的奇怪行为

Odd Behavior of Azure Service Bus ReceiveBatch()

目前正在使用 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 个。它似乎总是 return 在第一次民意调查中出现奇异值,然后在随后的民意调查中出现。 (与 3 和 5 的结果相同,第二次尝试发送 n 条消息中的 n-1 条,第一次尝试发送 1 条消息)。

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

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

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

我在 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:

Prefetching enables the queue or subscription client to load additional messages from the service when it performs a receive operation.

...

When using the default lock expiration of 60 seconds, a good value for SubscriptionClient.PrefetchCount is 20 times the maximum processing rates of all receivers of the factory. For example, a factory creates 3 receivers, and each receiver can process up to 10 messages per second. The prefetch count should not exceed 20*3*10 = 600.

...

Prefetching messages increases the overall throughput for a queue or subscription because it reduces the overall number of message operations, or round trips. Fetching the first message, however, will take longer (due to the increased message size). Receiving prefetched messages will be faster because these messages have already been downloaded by the client.

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

  1. 在主题中禁用分区(我必须为此创建一个新主题,因为创建后无法切换)
  2. 像这样创建的每个订阅启用批处理:
  3. 列表项

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

完成这两件事后,我可以使用 IEnumerable<BrokeredMessage> messageList = client.ReceiveBatch(100, new TimeSpan(0,0,0));

让主题按预期工作

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

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

所以它似乎是某种 corruption/bug 在服务总线的内存缓存中。