我们有pub / sub应用程序,涉及通过Azure Service Bus主题订阅Web角色发布者的外部客户端。我们当前的结算周期表示我们已发送/接收了> 25K消息,而我们的信息中心表示我们已发送< 100。我们正在调查我们的实施并检查我们的假设,以便了解这种差异。
作为调查的一部分,我们在客户端计算机上收集了客户端< =>服务总线流量的wireshark捕获。我们注意到了一种我们尚未见过的常规沟通模式,并且希望更好地理解。如果总线上没有活动,则每50秒进行一次以下交换:
一些相关信息:
问题
编辑:
这是接收消息的代码:
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();
}
答案 0 :(得分:7)
我认为您所看到的是后台接听电话。在幕后,接收呼叫都使用长轮询。这意味着他们呼叫服务总线端点并要求提供消息。 Service Bus服务获取该请求,如果有消息,它将立即返回。如果它没有消息,它将保持连接打开一段时间以防消息到达。如果消息在该时间范围内到达,则将其返回给客户端。如果在时间帧结束时消息不可用,则会向客户端发送响应,指示没有消息存在(也就是您的null BrokeredMessage)。如果您在没有重载的情况下调用Receive(就像您在此处所做的那样),它将立即发出另一个请求。此循环继续发生,直到收到消息。
因此,您所看到的是客户端请求消息但在那里没有消息的次数。长轮询使其比Windows Azure存储队列更好,因为如果没有消息,它们将立即返回null结果。对于这两种技术,通常会对请求实施指数退避。有很多关于如何做到这一点的例子。这会减少您检查队列的频率,并减少您的交易次数。
回答你的问题:
是的,这是正常的预期行为。
不,这只是一个交易。对于Service Bus,每次将消息放入队列并且每次请求消息时都会收取一笔交易(鉴于Recieve在后台多次拨打电话,这可能会有点不透明)。请注意,文档指出您需要为每个空闲事务收费(意味着来自Receive调用的结果为空)。
同样,您可以实施退避方法,以便您不会经常访问队列。我最近听到的另一个建议是,如果你有一个没有看到大量流量的队列,你也可以检查队列深度,看看它是否是&gt;在进入循环进行处理之前为0,如果从接收呼叫中没有收到任何消息,您可以返回查看队列深度。我没试过,如果你经常进行队列深度检查,你可能会受到限制。
如果这些是您的生产号码,那么您的订阅并不真正处理大量消息。在处理之前等待可以接受的时间可能是一个非常好的主意。比如,如果一条消息可以存在超过10分钟,那么创建一个退出方法,最终只需每10分钟检查一条消息,然后当它获得一个进程并立即再次检查时。
哦,有一个接收超载需要超时,但我不是100%,这是服务器超时或本地超时。如果它是本地的,那么它仍然可以每隔X秒向服务进行一次调用。我认为这是基于在创建SubscriptionClient时在Messaging Factory设置上设置的OperationTimeout值。你必须测试它。