Azure服务总线订阅服务器定期给家里打电话

本文关键字:打电话 服务器 服务 总线 Azure | 更新日期: 2023-09-27 18:30:13

我们有一个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. 我们看到的定期三包消息交换是由什么负责的?这是某种维持生命的方式吗
  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();
    }

Azure服务总线订阅服务器定期给家里打电话

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

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

回答您的问题:

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

  2. 不,这只是一笔交易。对于Service Bus,每次将消息放入队列和每次请求消息时,都会收取一笔交易费用(考虑到Recieve在后台多次拨打电话,这可能有点不透明)。请注意,文档指出,每个空闲事务(意味着Receive调用的结果为空)都会收取费用。

  3. 同样,您可以实现一种后退方法,这样就不会经常碰到队列。我最近听到的另一个建议是,如果你有一个没有看到很多流量的队列,你也可以在进入循环进行处理之前检查队列深度,看看它是否大于0,如果你没有收到来自接收呼叫的消息,你可以回去观察队列深度。我还没有尝试过,如果你经常检查队列深度,我想你可能会被抑制。

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

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