4

我们有 pub/sub 应用程序,其中涉及通过 Azure 服务总线主题订阅 Web 角色发布者的外部客户端。我们当前的计费周期表明我们已发送/接收 >25K 消息,而我们的仪表板表明我们已发送 <100 条消息。我们正在调查我们的实施并检查我们的假设以了解差异。

作为我们调查的一部分,我们收集了客户端机器上客户端<=>服务总线流量的wireshark捕获。我们注意到一种我们没有看到记录的常规通信模式,并且希望更好地理解。当总线上没有其他活动时,每 50 秒发生一次以下交换:

  1. 客户端将 ~200B 推送到服务总线。
  2. 10 秒后,服务总线将 ~800B 推送到客户端。客户端注册一个空消息的接收(通过断点确定。)
  3. 客户端立即响应,将 ~1000B 推送到服务总线。

一些相关信息:

  • 当我们的 Web 角色没有主动将数据推送到服务总线时,就会发生这种情况。
  • 在收到来自 Web 角色的合法消息后,上述模式将不会再次出现,直到整整 50 秒过去。
  • 客户端和服务器都通过 TCP 连接到 sb://命名空间.servicebus.windows.net。
  • 我们的应用程序消息 <64 KB

问题

  1. 我们看到的常规 3 包消息交换是由什么原因造成的?它是某种保活吗?
  2. 3 个数据包中的每一个都算作单独计费消息吗?
  3. 此行为是否可配置或以其他方式记录?

编辑:

这是接收消息的代码:

    private void Listen()
    {
        _subscriptionClient.ReceiveAsync().ContinueWith(MessageReceived);
    }

    private void MessageReceived(Task<BrokeredMessage> task)
    {
        if (task.Status != TaskStatus.Faulted && task.Result != null)
        {
            task.Result.CompleteAsync();
            // Do some things...
        }
        Listen();
    }
4

1 回答 1

7

我认为您看到的是后台接收呼叫。在幕后,接收呼叫都使用长轮询。这意味着他们调用服务总线端点并请求消息。服务总线服务获取该请求,如果它有消息,它将立即返回。如果它没有消息,它将保持连接打开一段时间,以防消息到达。如果消息在该时间范围内到达,它将返回给客户端。如果在时间范围结束时消息不可用,则会向客户端发送响应,指示那里没有消息(也就是您的 null BrokeredMessage)。如果您在没有重载的情况下调用 Receive(就像您在此处所做的那样),它将立即发出另一个请求。这个循环继续发生,直到收到消息。

因此,您看到的是客户端请求消息但那里没有消息的次数。长轮询使其比 Windows Azure 存储队列更好,因为如果没有消息,它们将立即返回空结果。对于这两种技术,对请求实施指数回退是很常见的。有很多关于如何做到这一点的例子。这减少了您需要检查队列的频率,并可以减少您的事务计数。

要回答您的问题:

  1. 是的,这是正常的预期行为。

  2. 不,这只是一笔交易。对于服务总线,每次将消息放入队列以及每次请求消息时都会向事务收费(考虑到 Recieve 在后台多次调用,这可能有点不透明)。请注意,文档指出您需要为每个空闲事务付费(意味着接收调用的结果为空)。

  3. 同样,您可以实施退避方法,这样您就不会经常排队。我最近听到的另一个建议是,如果您有一个没有看到大量流量的队列,您还可以在进入循环进行处理之前检查队列深度是否 > 0,如果您没有收到任何消息接听电话,您可以返回查看队列深度。我还没有尝试过,如果您过于频繁地进行队列深度检查,您可能会受到限制。

如果这些是您的生产编号,那么您的订阅并没有真正处理大量消息。在处理之前有一个可以接受等待的时间的回退策略可能是一个非常好的主意。就像,如果一条消息停留超过 10 分钟是可以的,那么创建一种回退方法,最终将每 10 分钟检查一次消息,然后当它得到一个处理并立即再次检查。

哦,有一个接收过载需要超时,但我不是 100% 是服务器超时或本地超时。如果它是本地的,那么它仍然可以每隔 X 秒对服务进行一次调用。我认为这是基于创建 SubscriptionClient 时在 Messaging Factory Settings 上设置的 OperationTimeout 值。你必须测试一下。

于 2013-09-03T20:27:06.887 回答