[rabbitmq-discuss] Exactly Once Delivery
Tim Fox
tim.fox at jboss.com
Mon Aug 9 11:49:42 BST 2010
On 07/08/10 12:50, Matthew Sackman wrote:
> On Fri, Aug 06, 2010 at 10:43:56PM +0100, Tim Fox wrote:
>
>> The way we do it in HornetQ is we have a well defined header key
>> "_HQ_DUP_ID". The client can set this with some unique value of it's
>> choice before sending (e.g. a GUID). When the server receives the
>> message if the _HQ_DUP_ID header is set, it looks up the value in
>> it's cache, and if it's seen it before it ignores it. The cache can
>> optionally be persisted.
>>
> How do you prevent the cache from growing without bound?
>
Currently we use a circular buffer. It's up to the user to make it big
enough for their use case. For JMS, where persistent sends/ tx commit
must be synchronous, the buffer size would need to be somewhat larger
than the max number of producers, since there's never more than one
"inflight" message at any time per producer. But there's certainly an
element of guesswork here.
In HornetQ we also provide an interface above and beyond JMS, which
allows the user to receive an *asynchronous* ack that the message they
sent (or tx commit) has been received ok on the server so they can clear
it from their local resend cache. Since this is async it's not limited
by network latency as in the blocking JMS case. The downside is many
messages can be in-flight at any time per producer so the caches need to
be larger.
To do all of this without being limited by arbitrary cache size, would
need some kind of "ack of ack" (we don't implement this yet)- i.e. 1)
the client sends message to server, 2) server sends ack back to to
client to say "received-ok" 3) client sends further ack from client to
server saying received-received-ok-ok. At point 2) the client can clear
their resend cache. At point 3) the server can clear it's cache. I
believe AMQP 1.0 specifies something similar to this too (?)
So.. this could scale. You'd have a further buffer per producer on the
server side. If you're using TCP on the server, then every connection
will have it's own buffer anyway. The extra buffer per producer should
be of the same order of size as the TCP buffer, since it's effectively
defined by a window, kind of similar to the TCP window size.
Like others have said, 100% once and only once delivery doesn't happen.
To get very near at 100% you can implement stuff like the above, and
also make sure your storage is highly redundant, also mirrored in
geographically distributed sites in case the building blows up. Then
you've got bugs in your own app, device drivers or the operating system
that screw your once and only once (for example last week I hit a bug in
the Linux kernel TCP impl which can cause packets to be lost at high
load) that you might hit well before having to take quantum effects into
account :)
> Matthew
> _______________________________________________
> rabbitmq-discuss mailing list
> rabbitmq-discuss at lists.rabbitmq.com
> https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss
>
--
Sent from my BBC Micro Model B
Tim Fox
JBoss
HornetQ - putting the buzz in messaging http://hornetq.org
http://hornetq.blogspot.com/
http://twitter.com/hornetq
irc://irc.freenode.net:6667#hornetq
fox at redhat.com
More information about the rabbitmq-discuss
mailing list