英文:
Does ServiceBusReceiver use a pull or a push communication model when talking to Azure Service Bus?
问题
调用和等待 ServiceBusReceiver.ReceiveMessageAsync()
或 ServiceBusReceiver.ReceiveMessageAsync(TimeSpan.FromMinutes(10))
时,幕后究竟发生了什么?
是:
a.) ServiceBusReceiver
从 Azure Service Bus 进行(长时间)轮询,还是
b.) Azure Service Bus 以某种方式向 ServiceBusReceiver
推送通知?
我尝试查看了 源代码,但没有取得多大进展,因为使用了一个名为 InnerReceiver
的类,我在代码库中找不到。
英文:
Just out of curiosity: What exactly happens behind the scenes when we call and await ServiceBusReceiver.ReceiveMessageAsync()
or ServiceBusReceiver.ReceiveMessageAsync(TimeSpan.FromMinutes(10))
?
Does
a.) the ServiceBusReceiver
(long-)poll Azure Service Bus or does
b.) Azure Service Bus send somehow push notifications to the ServiceBusReceiver
?
I tried to look into the source code, but didn't get far, because some class InnerReceiver
is used that I couldn't find in the code base.
答案1
得分: 6
在ServiceBus SDK层面上,它是一个拉取通信模型,只是为了更好地处理传入消息的确认。
但在幕后,Azure服务总线SDK使用了高级消息队列协议1.0,它不使用长轮询,而是在相同的AmqpConnection上使用AmqpLinks将数据从发送方发送到接收方,接收方将传入的消息保存到内存缓冲区中。
您可以在这里了解更多信息,或者观看Microsoft关于AMQP 1.0协议的视频系列。
所以看起来对于“幕后究竟发生了什么”的答案既不是A也不是B,消息被推送到ReceivingAmqpLink(到内存缓冲区),然后ServiceBusReceiver从中拉取。
我希望这个答案能结束这个讨论,大家都会很高兴
源代码:
ServiceBusReceiver
包装了 AmqpReceiver
包装了 AmqpReceiver
的 ReceiveMessagesAsync
在 AmqpReceiver
构造函数中创建 ReceivingAmqpLink
在可能的情况下在相同连接上打开 ReceivingAmqpLink
在 AmqpReceiver.ReceiveMessagesAsync
上调用那个“公共异步函数”
英文:
FINAL EDIT
On the ServiceBus Sdk level it is a pull communication model, just to better handle confirmation of incoming messages.
But behind the scenes azure service bus sdk uses Advanced Message Queuing Protocol 1.0 which doesn't long poll, it uses AmqpLink
s on the same AmqpConnection
to send data from a sender to a receiver, and the receiver saves the incoming messages to an in-memory buffer on receiving them.
You can read more about it here
or See this video series from Microsoft about the AMQP 1.0 protocol.
So it seems that the answer to "What exactly happens behind the scenes" is neither A nor B, Messages are being pushed to the ReceivingAmqpLink
(to an in-memory buffer), which then the ServiceBusReceiver
pulls from.
I hope this answer will close this discussion, and everyone will be happy
The source codes:
ServiceBusReceiver
wraps the AmqpReceiver
wrapping the ReceiveMessagesAsync
of the AmqpReceiver
Creating the ReceivingAmqpLink
in the constructor of the AmqpReceiver
Opening the ReceivingAmqpLink
on the same connection if possible
Caching the messages on the ReceivingAmqpLink
's buffer
Pulling the messages from the buffer into the ReceiveAsyncResult
The public async function that creates the ReceiveAsyncResult
Calling the that "public async function" on AmqpReceiver.ReceiveMessagesAsync
答案2
得分: 2
I think @Ethen.S answer is not correct. Moreover neither (a) nor (b) from original question are true:
- Service Bus in its core is pull based system (see https://learn.microsoft.com/en-us/azure/architecture/guide/technology-choices/messaging#pull-model)
ServiceBusReceiver.ReceiveMessageAsync
seems to be implemented in "async all the way" fashion as far as IO for this individual operation is concerned, meaning async operation is initiated, caller thread is "released" and then at some point async operation is completed upon notification and awaitedTasks
are completed, continuations queued, etc... Note that it does not mean that the wholeService Bus <-> Consumer
interaction can be considered a "push model" because aClient
of theServiceBusReceiver
has to do polling on top of it.- The only mentioned "push model" integration seems to be possible via Event Grid (see https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-to-event-grid-integration-concept?tabs=event-grid-event-schema)
You might want to take a look at Azure.Messaging.ServiceBus.ServiceBusProcessor
(use StartProcessingAsync
method as an entry point for investigation) source to better understand the dichotomy there. It exposes an event
that you subscribe to and handle the messages "reactively", but it still does a sequence of the ReceiveMessageAsync
for you. What might look "push" model from the consumer perspective might still rely on "poll" model behind the scenes.
Please also note that there is a concept of Message Prefetching
which can optimize some of the consumption scenarios, but it has its caveats to be considered as well (see https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-prefetch?tabs=dotnet#why-is-prefetch-not-the-default-option). It is still the same polling strategy, but with an additional client-level buffer on top.
UPDATE. I dug deeper into that to capture what happens on wire.
I've used sslsplit
in order to make MITM attack to capture TLS-protected AMQP connection decrypted data. Test application setup is simple:
- Receiver is doing
ReceiveMessageAsync
in a loop - After some time sender sends a message (two times)
In summary, this is indeed neither "poll" nor "push" as definitions are rather vague. What we can say for sure is that:
- it uses persistent TCP connection
- receival is controlled by the Client side using "Link Credit" (via the "flow" performative)
- when the client is idle waiting for messages once in about 30 seconds empty AMQP message is sent
- Service Bus has a mechanism to notify the receiver efficiently if there are enough "Link Credit."
I've put test code and test harness here: https://github.com/gubenkoved/amqp-test.
Below is the capture results, I've colored sender/receiver TCP streams as red/green.
英文:
I think @Ethen.S answer is not correct. Moreover neither (a) nor (b) from original question are true:
- Service Bus in its core is pull based system (see https://learn.microsoft.com/en-us/azure/architecture/guide/technology-choices/messaging#pull-model)
ServiceBusReceiver.ReceiveMessageAsync
seems to be implemented in "async all the way" fashion as far as IO for this individual operation is concerned, meaning async operation is initiated, caller thread is "released" and then at some point async operation is completed upon notification and awaitedTasks
are completed, continuations queued, etc... Note that it does not mean that the wholeService Bus <-> Consumer
interaction can be considered a "push model" because aClient
of theServiceBusReceiver
has to do polling on top of it.- The only mentioned "push model" integration seems to be possible via Event Grid (see https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-to-event-grid-integration-concept?tabs=event-grid-event-schema)
You might want to take a look at Azure.Messaging.ServiceBus.ServiceBusProcessor
(use StartProcessingAsync
method as an entry point for investigation) source to better understand the dichotomy there. It exposes an event
that you subscribe to and handle the messages "reactively", but it still does a sequence of the ReceiveMessageAsync
for you. What might look "push" model from the consumer perspective might still rely on "poll" model behind the scenes.
Please also note that there is a concept of Message Prefetching
which can optimise some of the consumption scenarios, but it has its caveats to be considered as well (see https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-prefetch?tabs=dotnet#why-is-prefetch-not-the-default-option). It is still the same polling strategy, but with an additional client-level buffer on top.
UPDATE. I dug deeper into that to capture what happens on wire.
I've used sslsplit
in order to make MITM attack to capture TLS-protected AMQP connection decrypted data. Test application setup is simple:
- Receiver is doing
ReceiveMessageAsync
in a loop - After some time sender sends a message (two times)
In summary, this is indeed neither "poll" nor "push" as definitions are rather vague. What we can say for sure is that:
- it uses persistent TCP connection
- receival is controlled by the Client side using "Link Credit" (via the "flow" performative)
- when client is idle waiting for messages once in about 30 seconds empty AMQP message is sent
- Service Bus has mechanism to notify the receiver efficiently if there are enough "Link Credit"
I've put test code and test harness here: https://github.com/gubenkoved/amqp-test.
Below is the capture results, I've colored sender/receiver TCP streams as red/green.
答案3
得分: 1
根据此部分的Azure应用架构指南,Azure Service Bus消费者在与Azure Service Bus通信时使用轮询模型:
拉取模型
Service Bus队列的消费者不断轮询Service Bus,以检查是否有新的消息可用。客户端SDK和Azure Functions触发器用于抽象该模型。当有新消息可用时,将调用消费者的回调函数,并将消息发送给消费者。
由于ServiceBusReceiver
是这样的消费者,它可能使用轮询。
英文:
According to this section of the Azure Application Architecture Guide, Azure Service Bus consumers use a poll model when talking to Azure Service Bus:
> Pull model
>
> A consumer of a Service Bus queue constantly polls Service Bus to check if new messages are available. The client SDKs and Azure Functions trigger for Service Bus abstract that model. When a new message is available, the consumer's callback is invoked and the message is sent to the consumer.
Since ServiceBusReceiver
is such a consumer, it probably uses polling.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论