7.2.7. Asynchronous Send and Link Reliability
The
sender.capacity
is the number of unacknowledged sends that a sender will allow when sending asynchronously. The two-phase send/acknowledge behavior is a characteristic of a reliable link (technically known as a link with at-least-once reliability). The sender sends a message, and buffers that message locally until the server responds to acknowledge receipt of the message. This buffering of unacknowledged sent messages enables the sender to resend messages (sender replay) if the link is dropped and then re-established. When a reliable link is dropped and then transparently re-established, messages that were sent asynchronously but not acknowledged by the server are resent from the sender replay buffer.
A reliable link is the default link used when creating a sender with no explicit link reliability specified. You can explicitly request an
unreliable
link when creating a sender. For example:
- Python
sender = session.sender("amq.topic;{link: {'reliability': 'unreliable'}}")
When using an
unreliable
link, sender capacity has no meaning. On an unreliable link the server does not acknowledge receipt of messages. All messages are considered as good as acknowledged once they are sent. This is the meaning of unreliable
for a sender. If the link is dropped there is no way for the sender to know which messages made it to the broker and which were lost. This also means that over an unreliable link asynchronous senders will not block, as their capacity is never utilized.
Sender.capacity
is used to limit the exposure of an application to data loss, and the amount of memory that senders can consume with their replay buffer. It can also be used to throttle producers. You can use an unreliable link along with asynchronous send to maximize throughput without the implications of local memory required for the sender replay buffer, and no throttling of producers. However, you must be aware of the reduced reliability and employ this pattern in situations where the potential for data loss is not important.
The following program demonstrates the difference between asynchronous sending over reliable and unreliable links:
- Python
import sys from qpid.messaging import * connection = Connection("localhost:5672") try: connection.open() session = connection.session() linktype="" while linktype != "R" and linktype !="U": response = raw_input("Use (R)eliable or (U)nreliable link [R/U]? ") linktype = response.upper() if linktype == "U": sender = session.sender("amq.topic;{link: {'reliability': 'unreliable'}}") else: sender = session.sender("amq.topic") message = Message("Hello World:") print sender.capacity sender.capacity = 5 for x in range (1000): if sender.available() == 0: print "Sender is blocking..." sender.send("Hello World: " + str(x), sync=False) print str(x) +" : " + str(sender.unsettled()) + " : " + str(sender.available()) except MessagingError,m: print m finally: connection.close()
The program sends 1000 messages asynchronously over a link using a sender with a capacity of 5 unacknowledged messages. The output takes the form:
message number : unacknowledged messages : further async send capacity
When run over a reliable link you will see the number of unacknowledged messages and the remaining async send capacity vary, including occasions where the asynchronous sender will block:
Use (R)eliable or (U)nreliable link [R/U]? R ... 918 : 1 : 4 919 : 2 : 3 920 : 3 : 2 921 : 4 : 1 922 : 5 : 0 Sender is blocking...
You can experiment with the value for
sender.capacity
(set to 5 in the program code) to see the impact it has on sender blocking.
When run over an unreliable link, you will see that
sender.capacity
has no impact on the performance of the sender. Remember, however, that it is now unreliable:
Use (R)eliable or (U)nreliable link [R/U]? U ... 984 : 0 : 5 985 : 0 : 5 986 : 0 : 5 987 : 0 : 5 988 : 0 : 5 989 : 0 : 5