You are viewing a plain text version of this content. The canonical link for it is here.
Posted to proton@qpid.apache.org by Michael Goulish <mg...@redhat.com> on 2013/03/01 15:40:35 UTC
[doc] rewrite of credit doc, to remove credit
I think Rafi brought up a kind of unassailable point when he
suggested that a document about the Messenger API should
probably confine itself to concepts that are ... in the Messenger API.
I would be happy to explain the use of credit sometime (after the impl
settles down...) but the Messenger API doc is not the place for that.
SO! here is a rewrite just describing how sending and receiving works,
without talking bout "links" "credit" or other concepts that the Messenger
API is specifically trying to shield the developer from.
- start - - start - - - start - - - - - start - - - - - - - start
===================================================
Messenger I/O
===================================================
Each messenger has a single queue of incoming messages,
and a single queue of outgoing messages. Both input and
output happen in two stages: between your application
and the queue, and between the queue and the senders
and receivers that your application is talking with.
Input
----------------------------------------
Incoming messages are received and placed on the
incoming queue with pn_messenger_recv(). The second
argument is the upper limit on how many messages will
be enqueued.
pn_messenger_recv ( messenger, 100 );
A call to pn_messenger_recv() will return when at least
one message is available, or when the call times out if
you have set a time limit with pn_messenger_set_timeout().
The call to pn_messenger_recv() may enqueue fewer than
the number of messages you allowed To find how many messages
it enqueued, use
int enqueued = pn_messenger_incoming ( messenger );
When you are ready to process your incoming messages,
dequeue them one at a time into your application:
( This is the second stage of message input. )
int i;
pn_message_t msg;
for ( i = 0; i < enqueued; ++ i )
{
pn_messenger_get ( messenger, & msg );
}
Output
-------------------------------------------
Output is also accomplished in two stages: first enqueing
as many messages as you wish, and and then transmitting them all.
Enqueue your messages one at a time with:
pn_messenger_put ( messenger, & msg );
To learn how many you have on the outgoing queue waiting to be
sent, use:
int outgoing = pn_messenger_outgoing ( messenger );
And to transmit the messages in your output queue:
pn_messenger_send ( messenger );
Unspecified Limits on Input
--------------------------------------------
By using -1 as the second argument to pn_messenger_recv(),
you let the Messenger implementation decide what limit to
set on how many messages you may receive.
It will give a chance to all senders that are currently connected
to your application, but will try to set a reasonable bound on
messages per sender.
Performance Implications
--------------------------------------------
Messaging system performance is always a tradeoff between
throughput and latency. Throughput is the number of messages
or number of bytes you can transmit and receive per unit time.
Latency is the average time between the creation of a message
by its sender, and its processing by a receiver.
The two-stage Messenger I/O model allows you to make whatever
balance you choose between throughput and latency.
If you build up larger batches of messages before transmitting,
your will improve your throughput at the expense of having a
higher average latency per message. Transmitting messages in
small batches, down to one at a time if you wish, will minimize
latency, but will increase transmission and computation overhead,
which will decrease throughput.
- end - - end - - - end - - - - - end - - - - - - - end
Re: [doc] rewrite of credit doc, to remove credit
Posted by Rafael Schloming <rh...@alum.mit.edu>.
On Fri, Mar 1, 2013 at 6:40 AM, Michael Goulish <mg...@redhat.com> wrote:
>
> I think Rafi brought up a kind of unassailable point when he
> suggested that a document about the Messenger API should
> probably confine itself to concepts that are ... in the Messenger API.
>
> I would be happy to explain the use of credit sometime (after the impl
> settles down...) but the Messenger API doc is not the place for that.
>
> SO! here is a rewrite just describing how sending and receiving works,
> without talking bout "links" "credit" or other concepts that the Messenger
> API is specifically trying to shield the developer from.
>
>
>
>
>
> - start - - start - - - start - - - - - start - - - - - - - start
>
>
>
>
>
> ===================================================
> Messenger I/O
> ===================================================
>
> Each messenger has a single queue of incoming messages,
> and a single queue of outgoing messages. Both input and
> output happen in two stages: between your application
> and the queue, and between the queue and the senders
> and receivers that your application is talking with.
>
I think this is already exposing too much implementation/deployment
topology. The app developer's model of the world should be much simpler
than this. A messenger deals in sending and receiving messages. The fact
that it might be receiving those messages from multiple parties or sending
them to multiple parties is not something that an app developer should be
concerned with.
>
>
>
> Input
> ----------------------------------------
>
> Incoming messages are received and placed on the
> incoming queue with pn_messenger_recv(). The second
> argument is the upper limit on how many messages will
> be enqueued.
>
>
> pn_messenger_recv ( messenger, 100 );
>
>
> A call to pn_messenger_recv() will return when at least
> one message is available, or when the call times out if
> you have set a time limit with pn_messenger_set_timeout().
>
> The call to pn_messenger_recv() may enqueue fewer than
> the number of messages you allowed To find how many messages
> it enqueued, use
>
>
> int enqueued = pn_messenger_incoming ( messenger );
>
>
> When you are ready to process your incoming messages,
> dequeue them one at a time into your application:
> ( This is the second stage of message input. )
>
>
> int i;
> pn_message_t msg;
>
> for ( i = 0; i < enqueued; ++ i )
> {
> pn_messenger_get ( messenger, & msg );
> }
>
>
>
I think it's awkward to describe pn_messenger_recv as enqueuing messages or
placing them on the incoming queue. It makes it sound like it should be
called pn_messenger_enqueue, e.g. the user might use it to enqueue a
message, but that is not what is actually happening. I don't think it's
necessary to describe how the messages get onto the incoming queue. That's
just implementation magic that a messenger does for you, not something you
do by calling recv. In fact messages can arrive pretty much anytime, not
just when you call recv. The key semantic of recv is that it will block
until there are messages in the queue (or the timeout expires).
>
>
>
> Output
> -------------------------------------------
>
> Output is also accomplished in two stages: first enqueing
> as many messages as you wish, and and then transmitting them all.
>
> Enqueue your messages one at a time with:
>
> pn_messenger_put ( messenger, & msg );
>
>
> To learn how many you have on the outgoing queue waiting to be
> sent, use:
>
> int outgoing = pn_messenger_outgoing ( messenger );
>
>
> And to transmit the messages in your output queue:
>
>
> pn_messenger_send ( messenger );
>
>
>
The semantics of pn_messenger_put allow it to send if it can do so without
blocking. There aren't really two stages here. The put vs send distinction
is more about separating the blocking and non blocking semantics into
separate calls.
>
>
>
> Unspecified Limits on Input
> --------------------------------------------
>
> By using -1 as the second argument to pn_messenger_recv(),
> you let the Messenger implementation decide what limit to
> set on how many messages you may receive.
>
> It will give a chance to all senders that are currently connected
> to your application, but will try to set a reasonable bound on
> messages per sender.
>
This reads like a footnote when actually it is probably the most common
case. I also think this is exposing aspects of the
implementation/deployment topology that the app developer shouldn't know
about, e.g. describing senders and referencing the effect on the flow
control algorithm. I would lead with the recv() case and follow up with the
recv(N) case as an "advanced" scenario.
>
>
>
>
>
> Performance Implications
> --------------------------------------------
>
> Messaging system performance is always a tradeoff between
> throughput and latency. Throughput is the number of messages
> or number of bytes you can transmit and receive per unit time.
> Latency is the average time between the creation of a message
> by its sender, and its processing by a receiver.
>
I don't think this is appropriate content for an intro. It's also not
really accurate. The tradeoff you speak of is often as much or more a
product of implementations rather than anything fundamental, and not all
implementations need to expose this tradeoff to users in order to make an
optimal choice.
> The two-stage Messenger I/O model allows you to make whatever
> balance you choose between throughput and latency.
>
It actually doesn't, pn_messenger_put is perfectly free to send messages,
it's just not free to block. The python docs actually state this:
Extracted from here:
http://qpid.apache.org/proton/api-doc/proton.Messenger-class.html
"""
Places the content contained in the message onto the outgoing
queue of the L{Messenger}. This method will never block, however
it will send any unblocked L{Messages<Message>} in the outgoing
queue immediately and leave any blocked L{Messages<Message>}
remaining in the outgoing queue. The L{send} call may be used to
block until the outgoing queue is empty. The L{outgoing} property
may be used to check the depth of the outgoing queue
....
"""
>
> If you build up larger batches of messages before transmitting,
> your will improve your throughput at the expense of having a
> higher average latency per message. Transmitting messages in
> small batches, down to one at a time if you wish, will minimize
> latency, but will increase transmission and computation overhead,
> which will decrease throughput.
>
I don't actually know what the impact is on computation, but it's not
obvious to me that it's what you state. I think in general we really
shouldn't talk about performance without actually measuring things, and
even then we should probably keep any performance statements out of
introductory material and somewhere in a context where the environment in
which measurements where made is quite clear.
--Rafael