blob: 46467d15aaedb9c47839a9acb885eef6d0d8f39a [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>Message Grouping</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>Message Grouping</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="#using-core-api">1. Using Core API</a></li>
<li><a href="#using-jms">2. Using JMS</a></li>
<li><a href="#closing-a-message-group">3. Closing a Message Group</a></li>
<li><a href="#notifying-consumer-of-group-ownership-change">4. Notifying Consumer of Group Ownership change</a></li>
<li><a href="#rebalancing-message-groups">5. Rebalancing Message Groups</a>
<ul class="sectlevel2">
<li><a href="#manually">5.1. Manually</a></li>
<li><a href="#automatically">5.2. Automatically</a></li>
</ul>
</li>
<li><a href="#group-buckets">6. Group Buckets</a></li>
<li><a href="#example">7. Example</a></li>
<li><a href="#clustered-grouping">8. Clustered Grouping</a>
<ul class="sectlevel2">
<li><a href="#clustered-grouping-configuration">8.1. Clustered Grouping Configuration</a></li>
<li><a href="#clustered-grouping-best-practices">8.2. Clustered Grouping Best Practices</a></li>
<li><a href="#clustered-grouping-example">8.3. Clustered Grouping Example</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Message groups are sets of messages that have the following characteristics:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Messages in a message group share the same group id, i.e. they have same group identifier property (<code>JMSXGroupID</code> for JMS, <code>_AMQ_GROUP_ID</code> for Apache ActiveMQ Artemis Core API).</p>
</li>
<li>
<p>Messages in a message group are always consumed by the same consumer, even if there are many consumers on a queue.
They pin all messages with the same group id to the same consumer.
If that consumer closes another consumer is chosen and will receive all messages with the same group id.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Message groups are useful when you want all messages for a certain value of the property to be processed serially by the same consumer.</p>
</div>
<div class="paragraph">
<p>An example might be orders for a certain stock.
You may want orders for any particular stock to be processed serially by the same consumer.
To do this you can create a pool of consumers (perhaps one for each stock, but less will work too), then set the stock name as the value of the _AMQ_GROUP_ID property.</p>
</div>
<div class="paragraph">
<p>This will ensure that all messages for a particular stock will always be processed by the same consumer.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Grouped messages can impact the concurrent processing of non-grouped messages due to the underlying FIFO semantics of a queue.
For example, if there is a chunk of 100 grouped messages at the head of a queue followed by 1,000 non-grouped messages then all the grouped messages will need to be sent to the appropriate client (which is consuming those grouped messages serially) before any of the non-grouped messages can be consumed.
The functional impact in this scenario is a temporary suspension of concurrent message processing while all the grouped messages are processed.
This can be a performance bottleneck so keep it in mind when determining the size of your message groups, and consider whether or not you should isolate your grouped messages from your non-grouped messages.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="using-core-api"><a class="anchor" href="#using-core-api"></a><a class="link" href="#using-core-api">1. Using Core API</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The property name used to identify the message group is <code>"_AMQ_GROUP_ID"</code> (or the constant <code>MessageImpl.HDR_GROUP_ID</code>).
Alternatively, you can set <code>autogroup</code> to true on the <code>SessionFactory</code> which will pick a random unique id.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="using-jms"><a class="anchor" href="#using-jms"></a><a class="link" href="#using-jms">2. Using JMS</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The property name used to identify the message group is <code>JMSXGroupID</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="java"><span class="c1">// send 2 messages in the same group to ensure the same</span>
<span class="c1">// consumer will receive both</span>
<span class="nc">Message</span> <span class="n">message</span> <span class="o">=</span> <span class="o">...</span>
<span class="n">message</span><span class="o">.</span><span class="na">setStringProperty</span><span class="o">(</span><span class="s">"JMSXGroupID"</span><span class="o">,</span> <span class="s">"Group-0"</span><span class="o">);</span>
<span class="n">producer</span><span class="o">.</span><span class="na">send</span><span class="o">(</span><span class="n">message</span><span class="o">);</span>
<span class="n">message</span> <span class="o">=</span> <span class="o">...</span>
<span class="n">message</span><span class="o">.</span><span class="na">setStringProperty</span><span class="o">(</span><span class="s">"JMSXGroupID"</span><span class="o">,</span> <span class="s">"Group-0"</span><span class="o">);</span>
<span class="n">producer</span><span class="o">.</span><span class="na">send</span><span class="o">(</span><span class="n">message</span><span class="o">);</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively, you can set <code>autogroup</code> to true on the <code>ActiveMQConnectonFactory</code> which will pick a random unique id.
This can also be set in the JNDI context environment, e.g. <code>jndi.properties</code>.
Here&#8217;s a simple example using the "ConnectionFactory" connection factory which is available in the context by default</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="properties"><span class="py">java.naming.factory.initial</span><span class="p">=</span><span class="s">org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory</span>
<span class="py">connectionFactory.myConnectionFactory</span><span class="p">=</span><span class="s">tcp://localhost:61616?autoGroup=true</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively you can set the group id via the connection factory.
All messages sent with producers created via this connection factory will set the <code>JMSXGroupID</code> to the specified value on all messages sent.
This can also be set in the JNDI context environment, e.g. <code>jndi.properties</code>.
Here&#8217;s a simple example using the "ConnectionFactory" connection factory which is available in the context by default:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="properties"><span class="py">java.naming.factory.initial</span><span class="p">=</span><span class="s">org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory</span>
<span class="py">connectionFactory.myConnectionFactory</span><span class="p">=</span><span class="s">tcp://localhost:61616?groupID=Group-0</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="closing-a-message-group"><a class="anchor" href="#closing-a-message-group"></a><a class="link" href="#closing-a-message-group">3. Closing a Message Group</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>You generally don&#8217;t need to close a message group, you just keep using it.
However, if you really do want to close a group you can add a negative sequence number.</p>
</div>
<div class="paragraph">
<p>Example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="java"><span class="nc">Message</span> <span class="n">message</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="na">createTextMessage</span><span class="o">(</span><span class="s">"&lt;foo&gt;hey&lt;/foo&gt;"</span><span class="o">);</span>
<span class="n">message</span><span class="o">.</span><span class="na">setStringProperty</span><span class="o">(</span><span class="s">"JMSXGroupID"</span><span class="o">,</span> <span class="s">"Group-0"</span><span class="o">);</span>
<span class="n">message</span><span class="o">.</span><span class="na">setIntProperty</span><span class="o">(</span><span class="s">"JMSXGroupSeq"</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">);</span>
<span class="o">...</span>
<span class="n">producer</span><span class="o">.</span><span class="na">send</span><span class="o">(</span><span class="n">message</span><span class="o">);</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This closes the message group so if another message is sent in the future with the same message group ID it will be reassigned to a new consumer.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="notifying-consumer-of-group-ownership-change"><a class="anchor" href="#notifying-consumer-of-group-ownership-change"></a><a class="link" href="#notifying-consumer-of-group-ownership-change">4. Notifying Consumer of Group Ownership change</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>ActiveMQ supports putting a boolean header on the first message sent to a consumer for a particular message group.</p>
</div>
<div class="paragraph">
<p>To enable this you must set a header key that the broker will use to set the flag.</p>
</div>
<div class="paragraph">
<p>In the examples we use <code>JMSXGroupFirstForConsumer</code> but it can be any header key value you want.</p>
</div>
<div class="paragraph">
<p>By setting <code>group-first-key</code> to <code>JMSXGroupFirstForConsumer</code> at the queue level, every time a new group is assigned a consumer the header <code>JMSXGroupFirstForConsumer</code> will be set to <code>true</code> on the first message.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address</span> <span class="na">name=</span><span class="s">"foo.bar"</span><span class="nt">&gt;</span>
<span class="nt">&lt;multicast&gt;</span>
<span class="nt">&lt;queue</span> <span class="na">name=</span><span class="s">"orders1"</span> <span class="na">group-first-key=</span><span class="s">"JMSXGroupFirstForConsumer"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/multicast&gt;</span>
<span class="nt">&lt;/address&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Or on auto-create when using the core JMS client by using address parameters when creating the destination used by the consumer.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="java"><span class="nc">Queue</span> <span class="n">queue</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="na">createQueue</span><span class="o">(</span><span class="s">"my.destination.name?group-first-key=JMSXGroupFirstForConsumer"</span><span class="o">);</span>
<span class="nc">Topic</span> <span class="n">topic</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="na">createTopic</span><span class="o">(</span><span class="s">"my.destination.name?group-first-key=JMSXGroupFirstForConsumer"</span><span class="o">);</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Also, the default for all queues under and address can be defaulted using the <code>address-setting</code> configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address-setting</span> <span class="na">match=</span><span class="s">"my.address"</span><span class="nt">&gt;</span>
<span class="nt">&lt;default-group-first-key&gt;</span>JMSXGroupFirstForConsumer<span class="nt">&lt;/default-group-first-key&gt;</span>
<span class="nt">&lt;/address-setting&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>By default, this is off.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="rebalancing-message-groups"><a class="anchor" href="#rebalancing-message-groups"></a><a class="link" href="#rebalancing-message-groups">5. Rebalancing Message Groups</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Sometimes after new consumers are added you can find that they have no groups assigned, and thus are not being utilised.
This is because all the groups are already assigned to existing consumers.
However, it is possible to rebalance the groups so that all the consumers are the queue are assigned one or more groups.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>At the exact moment of a reset a message to the originally associated consumer could be in flight at the same time a new message for the same group is dispatched to the new associated consumer.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="manually"><a class="anchor" href="#manually"></a><a class="link" href="#manually">5.1. Manually</a></h3>
<div class="paragraph">
<p>Use the management API (e.g via the web console) by invoking <code>resetAllGroups</code> on the associated queue.</p>
</div>
</div>
<div class="sect2">
<h3 id="automatically"><a class="anchor" href="#automatically"></a><a class="link" href="#automatically">5.2. Automatically</a></h3>
<div class="paragraph">
<p>By setting <code>group-rebalance</code> to <code>true</code> at the queue level every time a consumer is added it will trigger a rebalance/reset of the groups.</p>
</div>
<div class="paragraph">
<p>As noted above, when group rebalance is done there is a risk you may have inflight messages being processed.
By default, the broker will continue to dispatch whilst rebalance is occuring.
To ensure that inflight messages are processed before dispatch of new messages post rebalance, to different consumers, you can set <code>group-rebalance-pause-dispatch</code> to <code>true</code> which will cause the dispatch to pause whilst rebalance occurs until all inflight messages are processed.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address</span> <span class="na">name=</span><span class="s">"foo.bar"</span><span class="nt">&gt;</span>
<span class="nt">&lt;multicast&gt;</span>
<span class="nt">&lt;queue</span> <span class="na">name=</span><span class="s">"orders1"</span> <span class="na">group-rebalance=</span><span class="s">"true"</span> <span class="na">group-rebalance-pause-dispatch=</span><span class="s">"true"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/multicast&gt;</span>
<span class="nt">&lt;/address&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Or on auto-create when using the core JMS client by using address parameters when creating the destination used by the consumer.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="java"><span class="nc">Queue</span> <span class="n">queue</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="na">createQueue</span><span class="o">(</span><span class="s">"my.destination.name?group-rebalance=true&amp;group-rebalance-pause-dispatch=true"</span><span class="o">);</span>
<span class="nc">Topic</span> <span class="n">topic</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="na">createTopic</span><span class="o">(</span><span class="s">"my.destination.name?group-rebalance=true&amp;group-rebalance-pause-dispatch=true"</span><span class="o">);</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Also, the default for all queues under and address can be defaulted using the <code>address-setting</code> configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address-setting</span> <span class="na">match=</span><span class="s">"my.address"</span><span class="nt">&gt;</span>
<span class="nt">&lt;default-group-rebalance&gt;</span>true<span class="nt">&lt;/default-group-rebalance&gt;</span>
<span class="nt">&lt;default-group-rebalance-pause-dispatch&gt;</span>true<span class="nt">&lt;/default-group-rebalance-pause-dispatch&gt;</span>
<span class="nt">&lt;/address-setting&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>By default, <code>default-group-rebalance</code> is <code>false</code> meaning this is disabled/off.
By default, <code>default-group-rebalance-pause-dispatch</code> is <code>false</code> meaning this is disabled/off.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="group-buckets"><a class="anchor" href="#group-buckets"></a><a class="link" href="#group-buckets">6. Group Buckets</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>For handling groups in a queue with bounded memory allowing better scaling of groups, you can enable group buckets, essentially the group id is hashed into a bucket instead of keeping track of every single group id.</p>
</div>
<div class="paragraph">
<p>Setting <code>group-buckets</code> to <code>-1</code> keeps default behaviour which means the queue keeps track of every group but suffers from unbounded memory use.</p>
</div>
<div class="paragraph">
<p>Setting <code>group-buckets</code> to <code>0</code> disables grouping (0 buckets), on a queue.
This can be useful on a multicast address, where many queues exist but one queue you may not care for ordering and prefer to keep round robin behaviour.</p>
</div>
<div class="paragraph">
<p>There is a number of ways to set <code>group-buckets</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address</span> <span class="na">name=</span><span class="s">"foo.bar"</span><span class="nt">&gt;</span>
<span class="nt">&lt;multicast&gt;</span>
<span class="nt">&lt;queue</span> <span class="na">name=</span><span class="s">"orders1"</span> <span class="na">group-buckets=</span><span class="s">"1024"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/multicast&gt;</span>
<span class="nt">&lt;/address&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Specified on creating a Queue by using the CORE api specifying the parameter <code>group-buckets</code> to <code>20</code>.</p>
</div>
<div class="paragraph">
<p>Or on auto-create when using the JMS Client by using address parameters when creating the destination used by the consumer.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="java"><span class="nc">Queue</span> <span class="n">queue</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="na">createQueue</span><span class="o">(</span><span class="s">"my.destination.name?group-buckets=1024"</span><span class="o">);</span>
<span class="nc">Topic</span> <span class="n">topic</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="na">createTopic</span><span class="o">(</span><span class="s">"my.destination.name?group-buckets=1024"</span><span class="o">);</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Also the default for all queues under and address can be defaulted using the <code>address-setting</code> configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address-setting</span> <span class="na">match=</span><span class="s">"my.bucket.address"</span><span class="nt">&gt;</span>
<span class="nt">&lt;default-group-buckets&gt;</span>1024<span class="nt">&lt;/default-group-buckets&gt;</span>
<span class="nt">&lt;/address-setting&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>By default, <code>default-group-buckets</code> is <code>-1</code> this is to keep compatibility with existing default behaviour.</p>
</div>
<div class="paragraph">
<p>Address <a href="wildcard-syntax.html#wildcard-syntax">wildcards</a> can be used to configure group-buckets for a set of addresses.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="example"><a class="anchor" href="#example"></a><a class="link" href="#example">7. Example</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>See the <a href="examples.html#message-group">Message Group Example</a> which shows how message groups are configured and used with JMS and via a connection factory.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="clustered-grouping"><a class="anchor" href="#clustered-grouping"></a><a class="link" href="#clustered-grouping">8. Clustered Grouping</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Before looking at the details for configuring clustered grouping support it is worth examining the idea of clustered grouping as a whole.
In general, combining clustering and message grouping is a poor choice because the fundamental ideas of grouped (i.e. ordered) messages and horizontal scaling through clustering are essentially at odds with each other.</p>
</div>
<div class="paragraph">
<p>Message grouping enforces ordered message consumption.
Ordered message consumption requires that each message be fully consumed and acknowledged before the next message in the group is consumed.
This results in <em>serial</em> message processing (i.e. no concurrency).</p>
</div>
<div class="paragraph">
<p>However, the idea of clustering is to scale brokers horizontally in order to increase message throughput by adding consumers which can process messages concurrently.
But since the message groups are ordered the messages in each group cannot be consumed concurrently which defeats the purpose of horizontal scaling.</p>
</div>
<div class="paragraph">
<p><strong>Clustered grouping is not recommended</strong> for these reasons.</p>
</div>
<div class="paragraph">
<p>However, if you&#8217;ve evaluated your overall use-case with these design caveats in mind and have determined that clustered grouping is still viable then read on for all the configuration details and best practices.</p>
</div>
<div class="sect2">
<h3 id="clustered-grouping-configuration"><a class="anchor" href="#clustered-grouping-configuration"></a><a class="link" href="#clustered-grouping-configuration">8.1. Clustered Grouping Configuration</a></h3>
<div class="paragraph">
<p>Using message groups in a cluster is a bit more complex.
This is because messages with a particular group id can arrive on any node so each node needs to know about which group id&#8217;s are bound to which consumer on which node.
The consumer handling messages for a particular group id may be on a different node of the cluster, so each node needs to know this information so it can route the message correctly to the node which has that consumer.</p>
</div>
<div class="paragraph">
<p>To solve this there is the notion of a grouping handler.
Each node will have its own grouping handler and when a messages is sent with a group id assigned, the handlers will decide between them which route the message should take.</p>
</div>
<div class="paragraph">
<p>Here is a sample config for each type of handler.
This should be configured in <code>broker.xml</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;grouping-handler</span> <span class="na">name=</span><span class="s">"my-grouping-handler"</span><span class="nt">&gt;</span>
<span class="nt">&lt;type&gt;</span>LOCAL<span class="nt">&lt;/type&gt;</span>
<span class="nt">&lt;address&gt;</span>jms<span class="nt">&lt;/address&gt;</span>
<span class="nt">&lt;timeout&gt;</span>5000<span class="nt">&lt;/timeout&gt;</span>
<span class="nt">&lt;/grouping-handler&gt;</span>
<span class="nt">&lt;grouping-handler</span> <span class="na">name=</span><span class="s">"my-grouping-handler"</span><span class="nt">&gt;</span>
<span class="nt">&lt;type&gt;</span>REMOTE<span class="nt">&lt;/type&gt;</span>
<span class="nt">&lt;address&gt;</span>jms<span class="nt">&lt;/address&gt;</span>
<span class="nt">&lt;timeout&gt;</span>5000<span class="nt">&lt;/timeout&gt;</span>
<span class="nt">&lt;/grouping-handler&gt;</span></code></pre>
</div>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">type</dt>
<dd>
<p>Two types of handlers are supported - <code>LOCAL</code> and <code>REMOTE</code>.
Each cluster should choose 1 node to have a <code>LOCAL</code> grouping handler and all the other nodes should have <code>REMOTE</code> handlers.
It&#8217;s the <code>LOCAL</code> handler that actually makes the decision as to what route should be used, all the other <code>REMOTE</code> handlers converse with this.</p>
</dd>
<dt class="hdlist1">address</dt>
<dd>
<p>Refers to a <a href="clusters.html#configuring-cluster-connections">cluster connection and the address it uses</a>.
Refer to the clustering section on how to configure clusters.</p>
</dd>
<dt class="hdlist1">timeout</dt>
<dd>
<p>How long to wait for a decision to be made.
An exception will be thrown during the send if this timeout is reached, this ensures that strict ordering is kept.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>The decision as to where a message should be routed to is initially proposed by the node that receives the message.
The node will pick a suitable route as per the normal clustered routing conditions, i.e. round robin available queues, use a local queue first and choose a queue that has a consumer.
If the proposal is accepted by the grouping handlers the node will route messages to this queue from that point on, if rejected an alternative route will be offered and the node will again route to that queue indefinitely.
All other nodes will also route to the queue chosen at proposal time.
Once the message arrives at the queue then normal single server message group semantics take over and the message is pinned to a consumer on that queue.</p>
</div>
<div class="paragraph">
<p>You may have noticed that there is a single point of failure with the single local handler.
If this node crashes then no decisions will be able to be made.
Any messages sent will be not be delivered and an exception thrown.
To avoid this happening Local Handlers can be replicated on another backup node.
Simple create your back up node and configure it with the same Local handler.</p>
</div>
</div>
<div class="sect2">
<h3 id="clustered-grouping-best-practices"><a class="anchor" href="#clustered-grouping-best-practices"></a><a class="link" href="#clustered-grouping-best-practices">8.2. Clustered Grouping Best Practices</a></h3>
<div class="paragraph">
<p>Some best practices should be followed when using clustered grouping:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Make sure your consumers are distributed evenly across the different nodes if possible.
This is only an issue if you are creating and closing consumers regularly.
Since messages are always routed to the same queue once pinned, removing a consumer from this queue may leave it with no consumers meaning the queue will just keep receiving the messages.
Avoid closing consumers or make sure that you always have plenty of consumers, i.e., if you have 3 nodes have 3 consumers.</p>
</li>
<li>
<p>Use durable queues if possible.
If queues are removed once a group is bound to it, then it is possible that other nodes may still try to route messages to it.
This can be avoided by making sure that the queue is deleted by the session that is sending the messages.
This means that when the next message is sent it is sent to the node where the queue was deleted meaning a new proposal can successfully take place.
Alternatively you could just start using a different group id.</p>
</li>
<li>
<p>Always make sure that the node that has the Local Grouping Handler is replicated.
These means that on failover grouping will still occur.</p>
</li>
<li>
<p>In case you are using group-timeouts, the remote node should have a smaller group-timeout with at least half of the value on the main coordinator.
This is because this will determine how often the last-time-use value should be updated with a round trip for a request to the group between the nodes.</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="clustered-grouping-example"><a class="anchor" href="#clustered-grouping-example"></a><a class="link" href="#clustered-grouping-example">8.3. Clustered Grouping Example</a></h3>
<div class="paragraph">
<p>See the <a href="examples.html#clustered-grouping">Clustered Grouping Example</a> which shows how to configure message groups with a ActiveMQ Artemis Cluster.</p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>