blob: f6cb873844d50a5f197282c96be50425db32501b [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.18">
<link rel="icon" type="image/png" href="images/favicon.png">
<title>Ring Queue</title>
<link rel="stylesheet" href="css/asciidoctor.css">
<link rel="stylesheet" href="css/font-awesome.css">
<link rel="stylesheet" href="css/rouge-github.css">
</head>
<body class="book toc2 toc-left">
<div id="header">
<h1>Ring Queue</h1>
<div id="toc" class="toc2">
<div id="toctitle"><a href="index.html">User Manual for 2.33.0</a></div>
<ul class="sectlevel1">
<li><a href="#configuration">1. Configuration</a></li>
<li><a href="#messages-in-delivery-rollbacks">2. Messages in Delivery &amp; Rollbacks</a></li>
<li><a href="#scheduled-messages">3. Scheduled Messages</a></li>
<li><a href="#paging">4. Paging</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Queues operate with first-in, first-out (FIFO) semantics which means that messages, in general, are added to the "tail" of the queue and removed from the "head." A "ring" queue is a special type of queue with a <em>fixed</em> size.
The fixed size is maintained by removing the message at the head of the queue when the number of messages on the queue reaches the configured size.</p>
</div>
<div class="paragraph">
<p>For example, consider a queue configured with a ring size of 3 and a producer which sends the messages <code>A</code>, <code>B</code>, <code>C</code>, &amp; <code>D</code> in that order.
Once <code>C</code> is sent the number of messages in the queue will be 3 which is the same as the configured ring size.
We can visualize the queue growth like this&#8230;&#8203;</p>
</div>
<div class="paragraph">
<p>After <code>A</code> is sent:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="nowrap"> |---|
head/tail -&gt; | A |
|---|</pre>
</div>
</div>
<div class="paragraph">
<p>After <code>B</code> is sent:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="nowrap"> |---|
head -&gt; | A |
|---|
tail -&gt; | B |
|---|</pre>
</div>
</div>
<div class="paragraph">
<p>After <code>C</code> is sent:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="nowrap"> |---|
head -&gt; | A |
|---|
| B |
|---|
tail -&gt; | C |
|---|</pre>
</div>
</div>
<div class="paragraph">
<p>When <code>D</code> is sent it will be added to the tail of the queue and the message at the head of the queue (i.e. <code>A</code>) will be removed so the queue will look like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="nowrap"> |---|
head -&gt; | B |
|---|
| C |
|---|
tail -&gt; | D |
|---|</pre>
</div>
</div>
<div class="paragraph">
<p>This example covers the most basic use case with messages being added to the tail of the queue.
However, there are a few other important use cases involving:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Messages in delivery &amp; rollbacks</p>
</li>
<li>
<p>Scheduled messages</p>
</li>
<li>
<p>Paging</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>However, before we get to those use cases let&#8217;s look at the basic configuration of a ring queue.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configuration"><a class="anchor" href="#configuration"></a><a class="link" href="#configuration">1. Configuration</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>There are 2 parameters related to ring queue configuration.</p>
</div>
<div class="paragraph">
<p>The <code>ring-size</code> parameter can be set directly on the <code>queue</code> element.
The default value comes from the <code>default-ring-size</code> <code>address-setting</code> (see below).</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;addresses&gt;</span>
<span class="nt">&lt;address</span> <span class="na">name=</span><span class="s">"myRing"</span><span class="nt">&gt;</span>
<span class="nt">&lt;anycast&gt;</span>
<span class="nt">&lt;queue</span> <span class="na">name=</span><span class="s">"myRing"</span> <span class="na">ring-size=</span><span class="s">"3"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/anycast&gt;</span>
<span class="nt">&lt;/address&gt;</span>
<span class="nt">&lt;/addresses&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>default-ring-size</code> is an <code>address-setting</code> which applies to queues on matching addresses which don&#8217;t have an explicit <code>ring-size</code> set.
This is especially useful for auto-created queues.
The default value is <code>-1</code> (i.e. no limit).</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address-settings&gt;</span>
<span class="nt">&lt;address-setting</span> <span class="na">match=</span><span class="s">"ring.#"</span><span class="nt">&gt;</span>
<span class="nt">&lt;default-ring-size&gt;</span>3<span class="nt">&lt;/default-ring-size&gt;</span>
<span class="nt">&lt;/address-setting&gt;</span>
<span class="nt">&lt;/address-settings&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>ring-size</code> may be updated at runtime.
If the new <code>ring-size</code> is set <em>lower</em> than the previous <code>ring-size</code> the broker will not immediately delete enough messages from the head of the queue to enforce the new size.
New messages sent to the queue will force the deletion of old messages (i.e. the queue won&#8217;t grow any larger), but the queue will not reach its new size until it does so <em>naturally</em> through the normal consumption of messages by clients.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="messages-in-delivery-rollbacks"><a class="anchor" href="#messages-in-delivery-rollbacks"></a><a class="link" href="#messages-in-delivery-rollbacks">2. Messages in Delivery &amp; Rollbacks</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>When messages are "in delivery" they are in an in-between state where they are not technically on the queue but they are also not yet acknowledged.
The broker is at the consumer&#8217;s mercy to either acknowledge such messages or not.
In the context of a ring queue, messages which are in-delivery cannot be removed from the queue.</p>
</div>
<div class="paragraph">
<p>This presents a few dilemmas.</p>
</div>
<div class="paragraph">
<p>Due to the nature of messages in delivery a client can actually send more messages to a ring queue than it would otherwise permit.
This can make it appear that the ring-size is not being enforced properly.
Consider this simple scenario:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Queue <code>foo</code> with <code>ring-size="3"</code></p>
</li>
<li>
<p>1 Consumer on queue <code>foo</code></p>
</li>
<li>
<p>Message <code>A</code> sent to <code>foo</code> &amp; dispatched to consumer</p>
</li>
<li>
<p><code>messageCount</code>=1, <code>deliveringCount</code>=1</p>
</li>
<li>
<p>Message <code>B</code> sent to <code>foo</code> &amp; dispatched to consumer</p>
</li>
<li>
<p><code>messageCount</code>=2, <code>deliveringCount</code>=2</p>
</li>
<li>
<p>Message <code>C</code> sent to <code>foo</code> &amp; dispatched to consumer</p>
</li>
<li>
<p><code>messageCount</code>=3, <code>deliveringCount</code>=3</p>
</li>
<li>
<p>Message <code>D</code> sent to <code>foo</code> &amp; dispatched to consumer</p>
</li>
<li>
<p><code>messageCount</code>=4, <code>deliveringCount</code>=4</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>messageCount</code> for <code>foo</code> is now 4, one <em>greater</em> than the <code>ring-size</code> of 3!
However, the broker has no choice but to allow this because it cannot remove messages from the queue which are in delivery.</p>
</div>
<div class="paragraph">
<p>Now consider that the consumer is closed without actually acknowledging any of these 4 messages.
These 4 in-delivery, unacknowledged messages will be cancelled back to the broker and added to the <em>head</em> of the queue in the reverse order from which they were consumed.
This, of course, will put the queue over its configured <code>ring-size</code>.
Therefore, since a ring queue prefers messages at the tail of the queue over messages at the head it will keep <code>B</code>, <code>C</code>, &amp; <code>D</code> and delete <code>A</code> (since <code>A</code> was the last message added to the head of the queue).</p>
</div>
<div class="paragraph">
<p>Transaction or core session rollbacks are treated the same way.</p>
</div>
<div class="paragraph">
<p>If you wish to avoid these kinds of situations and you&#8217;re using the core client directly or the core JMS client you can minimize messages in delivery by reducing the size of <code>consumerWindowSize</code> (1024 * 1024 bytes by default).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="scheduled-messages"><a class="anchor" href="#scheduled-messages"></a><a class="link" href="#scheduled-messages">3. Scheduled Messages</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>When a scheduled message is sent to a queue it isn&#8217;t immediately added to the tail of the queue like normal messages.
It is held in an intermediate buffer and scheduled for delivery onto the <em>head</em> of the queue according to the details of the message.
However, scheduled messages are nevertheless reflected in the message count of the queue.
As with messages which are in delivery this can make it appear that the ring queue&#8217;s size is not being enforced.
Consider this simple scenario:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Queue <code>foo</code> with <code>ring-size="3"</code></p>
</li>
<li>
<p>At 12:00 message <code>A</code> sent to <code>foo</code> scheduled for 12:05</p>
</li>
<li>
<p><code>messageCount</code>=1, <code>scheduledCount</code>=1</p>
</li>
<li>
<p>At 12:01 message <code>B</code> sent to <code>foo</code></p>
</li>
<li>
<p><code>messageCount</code>=2, <code>scheduledCount</code>=1</p>
</li>
<li>
<p>At 12:02 message <code>C</code> sent to <code>foo</code></p>
</li>
<li>
<p><code>messageCount</code>=3, <code>scheduledCount</code>=1</p>
</li>
<li>
<p>At 12:03 message <code>D</code> sent to <code>foo</code></p>
</li>
<li>
<p><code>messageCount</code>=4, <code>scheduledCount</code>=1</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>messageCount</code> for <code>foo</code> is now 4, one <em>greater</em> than the <code>ring-size</code> of 3!
However, the scheduled message is not technically on the queue yet (i.e. it is on the broker and scheduled to be put on the queue).
When the scheduled delivery time for 12:05 comes the message will put on the head of the queue, but since the ring queue&#8217;s size has already been reach the scheduled message <code>A</code> will be removed.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="paging"><a class="anchor" href="#paging"></a><a class="link" href="#paging">4. Paging</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Similar to scheduled messages and messages in delivery, paged messages don&#8217;t count against a ring queue&#8217;s size because messages are actually paged at the <em>address</em> level, not the queue level.
A paged message is not technically on a queue although it is reflected in a queue&#8217;s <code>messageCount</code>.</p>
</div>
<div class="paragraph">
<p>It is recommended that paging is not used for addresses with ring queues.
In other words, ensure that the entire address will be able to fit into memory or use the <code>DROP</code>, <code>BLOCK</code> or <code>FAIL</code> <code>address-full-policy</code>.</p>
</div>
</div>
</div>
</div>
</body>
</html>