blob: 2346e7974338c1ec4fd92b191288daa9b9b7f1dc [file] [log] [blame]
<!DOCTYPE HTML>
<html lang="" >
<head>
<title>Message Grouping ยท ActiveMQ Artemis Documentation</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="generator" content="GitBook 3.1.1">
<link rel="stylesheet" href="gitbook/style.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-highlight/website.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-search/search.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
<meta name="HandheldFriendly" content="true"/>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
<link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">
<link rel="next" href="consumer-priority.html" />
<link rel="prev" href="exclusive-queues.html" />
</head>
<body>
<div class="book">
<div class="book-summary">
<div id="book-search-input" role="search">
<input type="text" placeholder="Type to search" />
</div>
<nav role="navigation">
<ul class="summary">
<li class="chapter " data-level="1.1" data-path="./">
<a href="./">
Introduction
</a>
</li>
<li class="chapter " data-level="1.2" data-path="notice.html">
<a href="notice.html">
Legal Notice
</a>
</li>
<li class="chapter " data-level="1.3" data-path="preface.html">
<a href="preface.html">
Preface
</a>
</li>
<li class="chapter " data-level="1.4" data-path="project-info.html">
<a href="project-info.html">
Project Info
</a>
</li>
<li class="chapter " data-level="1.5" data-path="versions.html">
<a href="versions.html">
Versions
</a>
</li>
<li class="chapter " data-level="1.6" data-path="messaging-concepts.html">
<a href="messaging-concepts.html">
Messaging Concepts
</a>
</li>
<li class="chapter " data-level="1.7" data-path="architecture.html">
<a href="architecture.html">
Architecture
</a>
</li>
<li class="chapter " data-level="1.8" data-path="using-server.html">
<a href="using-server.html">
Using the Server
</a>
</li>
<li class="chapter " data-level="1.9" data-path="upgrading.html">
<a href="upgrading.html">
Upgrading
</a>
</li>
<li class="chapter " data-level="1.10" data-path="address-model.html">
<a href="address-model.html">
Address Model
</a>
</li>
<li class="chapter " data-level="1.11" data-path="protocols-interoperability.html">
<a href="protocols-interoperability.html">
Protocols and Interoperability
</a>
</li>
<li class="chapter " data-level="1.12" data-path="amqp.html">
<a href="amqp.html">
AMQP
</a>
</li>
<li class="chapter " data-level="1.13" data-path="mqtt.html">
<a href="mqtt.html">
MQTT
</a>
</li>
<li class="chapter " data-level="1.14" data-path="stomp.html">
<a href="stomp.html">
STOMP
</a>
</li>
<li class="chapter " data-level="1.15" data-path="openwire.html">
<a href="openwire.html">
OpenWire
</a>
</li>
<li class="chapter " data-level="1.16" data-path="core.html">
<a href="core.html">
Core
</a>
</li>
<li class="chapter " data-level="1.17" data-path="jms-core-mapping.html">
<a href="jms-core-mapping.html">
Mapping JMS Concepts to the Core API
</a>
</li>
<li class="chapter " data-level="1.18" data-path="using-jms.html">
<a href="using-jms.html">
Using JMS
</a>
</li>
<li class="chapter " data-level="1.19" data-path="client-classpath.html">
<a href="client-classpath.html">
The Client Classpath
</a>
</li>
<li class="chapter " data-level="1.20" data-path="examples.html">
<a href="examples.html">
Examples
</a>
</li>
<li class="chapter " data-level="1.21" data-path="wildcard-routing.html">
<a href="wildcard-routing.html">
Routing Messages With Wild Cards
</a>
</li>
<li class="chapter " data-level="1.22" data-path="wildcard-syntax.html">
<a href="wildcard-syntax.html">
Wildcard Syntax
</a>
</li>
<li class="chapter " data-level="1.23" data-path="filter-expressions.html">
<a href="filter-expressions.html">
Filter Expressions
</a>
</li>
<li class="chapter " data-level="1.24" data-path="persistence.html">
<a href="persistence.html">
Persistence
</a>
</li>
<li class="chapter " data-level="1.25" data-path="configuring-transports.html">
<a href="configuring-transports.html">
Configuring Transports
</a>
</li>
<li class="chapter " data-level="1.26" data-path="config-reload.html">
<a href="config-reload.html">
Configuration Reload
</a>
</li>
<li class="chapter " data-level="1.27" data-path="connection-ttl.html">
<a href="connection-ttl.html">
Detecting Dead Connections
</a>
</li>
<li class="chapter " data-level="1.28" data-path="slow-consumers.html">
<a href="slow-consumers.html">
Detecting Slow Consumers
</a>
</li>
<li class="chapter " data-level="1.29" data-path="network-isolation.html">
<a href="network-isolation.html">
Avoiding Network Isolation
</a>
</li>
<li class="chapter " data-level="1.30" data-path="critical-analysis.html">
<a href="critical-analysis.html">
Detecting Broker Issues (Critical Analysis)
</a>
</li>
<li class="chapter " data-level="1.31" data-path="transaction-config.html">
<a href="transaction-config.html">
Resource Manager Configuration
</a>
</li>
<li class="chapter " data-level="1.32" data-path="flow-control.html">
<a href="flow-control.html">
Flow Control
</a>
</li>
<li class="chapter " data-level="1.33" data-path="send-guarantees.html">
<a href="send-guarantees.html">
Guarantees of sends and commits
</a>
</li>
<li class="chapter " data-level="1.34" data-path="undelivered-messages.html">
<a href="undelivered-messages.html">
Message Redelivery and Undelivered Messages
</a>
</li>
<li class="chapter " data-level="1.35" data-path="message-expiry.html">
<a href="message-expiry.html">
Message Expiry
</a>
</li>
<li class="chapter " data-level="1.36" data-path="large-messages.html">
<a href="large-messages.html">
Large Messages
</a>
</li>
<li class="chapter " data-level="1.37" data-path="paging.html">
<a href="paging.html">
Paging
</a>
</li>
<li class="chapter " data-level="1.38" data-path="scheduled-messages.html">
<a href="scheduled-messages.html">
Scheduled Messages
</a>
</li>
<li class="chapter " data-level="1.39" data-path="last-value-queues.html">
<a href="last-value-queues.html">
Last-Value Queues
</a>
</li>
<li class="chapter " data-level="1.40" data-path="ring-queues.html">
<a href="ring-queues.html">
Ring Queues
</a>
</li>
<li class="chapter " data-level="1.41" data-path="retroactive-addresses.html">
<a href="retroactive-addresses.html">
Retroactive Addresses
</a>
</li>
<li class="chapter " data-level="1.42" data-path="exclusive-queues.html">
<a href="exclusive-queues.html">
Exclusive Queues
</a>
</li>
<li class="chapter active" data-level="1.43" data-path="message-grouping.html">
<a href="message-grouping.html">
Message Grouping
</a>
</li>
<li class="chapter " data-level="1.44" data-path="consumer-priority.html">
<a href="consumer-priority.html">
Consumer Priority
</a>
</li>
<li class="chapter " data-level="1.45" data-path="pre-acknowledge.html">
<a href="pre-acknowledge.html">
Extra Acknowledge Modes
</a>
</li>
<li class="chapter " data-level="1.46" data-path="management.html">
<a href="management.html">
Management
</a>
</li>
<li class="chapter " data-level="1.47" data-path="management-console.html">
<a href="management-console.html">
Management Console
</a>
</li>
<li class="chapter " data-level="1.48" data-path="metrics.html">
<a href="metrics.html">
Metrics
</a>
</li>
<li class="chapter " data-level="1.49" data-path="security.html">
<a href="security.html">
Security
</a>
</li>
<li class="chapter " data-level="1.50" data-path="masking-passwords.html">
<a href="masking-passwords.html">
Masking Passwords
</a>
</li>
<li class="chapter " data-level="1.51" data-path="broker-plugins.html">
<a href="broker-plugins.html">
Broker Plugins
</a>
</li>
<li class="chapter " data-level="1.52" data-path="resource-limits.html">
<a href="resource-limits.html">
Resource Limits
</a>
</li>
<li class="chapter " data-level="1.53" data-path="jms-bridge.html">
<a href="jms-bridge.html">
The JMS Bridge
</a>
</li>
<li class="chapter " data-level="1.54" data-path="client-reconnection.html">
<a href="client-reconnection.html">
Client Reconnection and Session Reattachment
</a>
</li>
<li class="chapter " data-level="1.55" data-path="diverts.html">
<a href="diverts.html">
Diverting and Splitting Message Flows
</a>
</li>
<li class="chapter " data-level="1.56" data-path="core-bridges.html">
<a href="core-bridges.html">
Core Bridges
</a>
</li>
<li class="chapter " data-level="1.57" data-path="transformers.html">
<a href="transformers.html">
Transformers
</a>
</li>
<li class="chapter " data-level="1.58" data-path="duplicate-detection.html">
<a href="duplicate-detection.html">
Duplicate Message Detection
</a>
</li>
<li class="chapter " data-level="1.59" data-path="clusters.html">
<a href="clusters.html">
Clusters
</a>
</li>
<li class="chapter " data-level="1.60" data-path="federation.html">
<a href="federation.html">
Federation
</a>
<ul class="articles">
<li class="chapter " data-level="1.60.1" data-path="federation-address.html">
<a href="federation-address.html">
Address Federation
</a>
</li>
<li class="chapter " data-level="1.60.2" data-path="federation-queue.html">
<a href="federation-queue.html">
Queue Federation
</a>
</li>
</ul>
</li>
<li class="chapter " data-level="1.61" data-path="ha.html">
<a href="ha.html">
High Availability and Failover
</a>
</li>
<li class="chapter " data-level="1.62" data-path="graceful-shutdown.html">
<a href="graceful-shutdown.html">
Graceful Server Shutdown
</a>
</li>
<li class="chapter " data-level="1.63" data-path="libaio.html">
<a href="libaio.html">
Libaio Native Libraries
</a>
</li>
<li class="chapter " data-level="1.64" data-path="thread-pooling.html">
<a href="thread-pooling.html">
Thread management
</a>
</li>
<li class="chapter " data-level="1.65" data-path="web-server.html">
<a href="web-server.html">
Embedded Web Server
</a>
</li>
<li class="chapter " data-level="1.66" data-path="logging.html">
<a href="logging.html">
Logging
</a>
</li>
<li class="chapter " data-level="1.67" data-path="rest.html">
<a href="rest.html">
REST Interface
</a>
</li>
<li class="chapter " data-level="1.68" data-path="embedding-activemq.html">
<a href="embedding-activemq.html">
Embedding the Broker
</a>
</li>
<li class="chapter " data-level="1.69" data-path="karaf.html">
<a href="karaf.html">
Apache Karaf
</a>
</li>
<li class="chapter " data-level="1.70" data-path="tomcat.html">
<a href="tomcat.html">
Apache Tomcat
</a>
</li>
<li class="chapter " data-level="1.71" data-path="spring-integration.html">
<a href="spring-integration.html">
Spring Integration
</a>
</li>
<li class="chapter " data-level="1.72" data-path="cdi-integration.html">
<a href="cdi-integration.html">
CDI Integration
</a>
</li>
<li class="chapter " data-level="1.73" data-path="intercepting-operations.html">
<a href="intercepting-operations.html">
Intercepting Operations
</a>
</li>
<li class="chapter " data-level="1.74" data-path="data-tools.html">
<a href="data-tools.html">
Data Tools
</a>
</li>
<li class="chapter " data-level="1.75" data-path="maven-plugin.html">
<a href="maven-plugin.html">
Maven Plugin
</a>
</li>
<li class="chapter " data-level="1.76" data-path="unit-testing.html">
<a href="unit-testing.html">
Unit Testing
</a>
</li>
<li class="chapter " data-level="1.77" data-path="perf-tuning.html">
<a href="perf-tuning.html">
Troubleshooting and Performance Tuning
</a>
</li>
<li class="chapter " data-level="1.78" data-path="configuration-index.html">
<a href="configuration-index.html">
Configuration Reference
</a>
</li>
<li class="divider"></li>
<li>
<a href="https://www.gitbook.com" target="blank" class="gitbook-link">
Published with GitBook
</a>
</li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<!-- Title -->
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i>
<a href="." >Message Grouping</a>
</h1>
</div>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<div id="book-search-results">
<div class="search-noresults">
<section class="normal markdown-section">
<h1 id="message-grouping">Message Grouping</h1>
<p>Message groups are sets of messages that have the following characteristics:</p>
<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>
<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>
<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>
<p>This will ensure that all messages for a particular stock will always be
processed by the same consumer.</p>
<blockquote>
<p><strong>Note:</strong></p>
<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>
</blockquote>
<h2 id="using-core-api">Using Core API</h2>
<p>The property name used to identify the message group is <code>&quot;_AMQ_GROUP_ID&quot;</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>
<h2 id="using-jms">Using JMS</h2>
<p>The property name used to identify the message group is <code>JMSXGroupID</code>.</p>
<pre><code class="lang-java"><span class="hljs-comment">// send 2 messages in the same group to ensure the same</span>
<span class="hljs-comment">// consumer will receive both</span>
Message message = ...
message.setStringProperty(<span class="hljs-string">&quot;JMSXGroupID&quot;</span>, <span class="hljs-string">&quot;Group-0&quot;</span>);
producer.send(message);
message = ...
message.setStringProperty(<span class="hljs-string">&quot;JMSXGroupID&quot;</span>, <span class="hljs-string">&quot;Group-0&quot;</span>);
producer.send(message);
</code></pre>
<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&apos;s a simple
example using the &quot;ConnectionFactory&quot; connection factory which is available in
the context by default</p>
<pre><code class="lang-properties">java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
connectionFactory.myConnectionFactory=tcp://localhost:61616?autoGroup=true
</code></pre>
<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&apos;s a simple
example using the &quot;ConnectionFactory&quot; connection factory which is available in
the context by default:</p>
<pre><code class="lang-properties">java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
connectionFactory.myConnectionFactory=tcp://localhost:61616?groupID=Group-0
</code></pre>
<h4 id="closing-a-message-group">Closing a Message Group</h4>
<p>You generally don&apos;t need to close a message group, you just keep using it. </p>
<p>However if you really do want to close a group you can add a negative sequence number.</p>
<p>Example:</p>
<pre><code class="lang-java">Mesasge message = session.createTextMessage(<span class="hljs-string">&quot;&lt;foo&gt;hey&lt;/foo&gt;&quot;</span>);
message.setStringProperty(<span class="hljs-string">&quot;JMSXGroupID&quot;</span>, <span class="hljs-string">&quot;Group-0&quot;</span>);
message.setIntProperty(<span class="hljs-string">&quot;JMSXGroupSeq&quot;</span>, -<span class="hljs-number">1</span>);
...
producer.send(message);
</code></pre>
<p>This then 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>
<h4 id="notifying-consumer-of-group-ownership-change">Notifying Consumer of Group Ownership change</h4>
<p>ActiveMQ supports putting a boolean header, set on the first message sent to a consumer for a particular message group.</p>
<p>To enable this, you must set a header key that the broker will use to set the flag.</p>
<p>In the examples we use <code>JMSXGroupFirstForConsumer</code> but it can be any header key value you want.</p>
<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 true on the first message.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">address</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;foo.bar&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">multicast</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">queue</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;orders1&quot;</span> <span class="hljs-attr">group-first-key</span>=<span class="hljs-string">&quot;JMSXGroupFirstForConsumer&quot;</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">multicast</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">address</span>&gt;</span>
</code></pre>
<p>Or on auto-create when using the JMS Client by using address parameters when
creating the destination used by the consumer.</p>
<pre><code class="lang-java">Queue queue = session.createQueue(<span class="hljs-string">&quot;my.destination.name?group-first-key=JMSXGroupFirstForConsumer&quot;</span>);
Topic topic = session.createTopic(<span class="hljs-string">&quot;my.destination.name?group-first-key=JMSXGroupFirstForConsumer&quot;</span>);
</code></pre>
<p>Also the default for all queues under and address can be defaulted using the
<code>address-setting</code> configuration:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">address-setting</span> <span class="hljs-attr">match</span>=<span class="hljs-string">&quot;my.address&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">default-group-first-key</span>&gt;</span>JMSXGroupFirstForConsumer<span class="hljs-tag">&lt;/<span class="hljs-name">default-group-first-key</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">address-setting</span>&gt;</span>
</code></pre>
<p>By default this is null, and therefor OFF. </p>
<h4 id="rebalancing-message-groups">Rebalancing Message Groups</h4>
<p>Sometimes after new consumers are added you can find that if you have long lived groups, that they have no groups assigned, and thus are not being utilised, this is because the long lived groups will already be assigned to existing consumers.</p>
<p>It is possibly to rebalance the groups.</p>
<p><strong><em>note</em></strong> during the split moment of reset, a message to the original 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>
<h5 id="manually">Manually</h5>
<p>via the management API or managment console by invoking <code>resetAllGroups</code></p>
<h5 id="automatically">Automatically</h5>
<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>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">address</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;foo.bar&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">multicast</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">queue</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;orders1&quot;</span> <span class="hljs-attr">group-rebalance</span>=<span class="hljs-string">&quot;true&quot;</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">multicast</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">address</span>&gt;</span>
</code></pre>
<p>Or on auto-create when using the JMS Client by using address parameters when
creating the destination used by the consumer.</p>
<pre><code class="lang-java">Queue queue = session.createQueue(<span class="hljs-string">&quot;my.destination.name?group-rebalance=true&quot;</span>);
Topic topic = session.createTopic(<span class="hljs-string">&quot;my.destination.name?group-rebalance=true&quot;</span>);
</code></pre>
<p>Also the default for all queues under and address can be defaulted using the
<code>address-setting</code> configuration:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">address-setting</span> <span class="hljs-attr">match</span>=<span class="hljs-string">&quot;my.address&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">default-group-rebalance</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">default-group-rebalance</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">address-setting</span>&gt;</span>
</code></pre>
<p>By default, <code>default-group-rebalance</code> is <code>false</code> meaning this is disabled/off.</p>
<h4 id="group-buckets">Group Buckets</h4>
<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>
<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>
<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>
<p>There is a number of ways to set <code>group-buckets</code>.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">address</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;foo.bar&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">multicast</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">queue</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;orders1&quot;</span> <span class="hljs-attr">group-buckets</span>=<span class="hljs-string">&quot;1024&quot;</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">multicast</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">address</span>&gt;</span>
</code></pre>
<p>Specified on creating a Queue by using the CORE api specifying the parameter
<code>group-buckets</code> to <code>20</code>. </p>
<p>Or on auto-create when using the JMS Client by using address parameters when
creating the destination used by the consumer.</p>
<pre><code class="lang-java">Queue queue = session.createQueue(<span class="hljs-string">&quot;my.destination.name?group-buckets=1024&quot;</span>);
Topic topic = session.createTopic(<span class="hljs-string">&quot;my.destination.name?group-buckets=1024&quot;</span>);
</code></pre>
<p>Also the default for all queues under and address can be defaulted using the
<code>address-setting</code> configuration:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">address-setting</span> <span class="hljs-attr">match</span>=<span class="hljs-string">&quot;my.bucket.address&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">default-group-buckets</span>&gt;</span>1024<span class="hljs-tag">&lt;/<span class="hljs-name">default-group-buckets</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">address-setting</span>&gt;</span>
</code></pre>
<p>By default, <code>default-group-buckets</code> is <code>-1</code> this is to keep compatibility with existing default behaviour. </p>
<p>Address <a href="wildcard-syntax.html">wildcards</a> can be used to configure group-buckets for a
set of addresses.</p>
<h2 id="example">Example</h2>
<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>
<h2 id="clustered-grouping">Clustered Grouping</h2>
<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&apos;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>
<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>
<p>Here is a sample config for each type of handler. This should be configured in
<code>broker.xml</code>.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">grouping-handler</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;my-grouping-handler&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">type</span>&gt;</span>LOCAL<span class="hljs-tag">&lt;/<span class="hljs-name">type</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">address</span>&gt;</span>jms<span class="hljs-tag">&lt;/<span class="hljs-name">address</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">timeout</span>&gt;</span>5000<span class="hljs-tag">&lt;/<span class="hljs-name">timeout</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">grouping-handler</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">grouping-handler</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;my-grouping-handler&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">type</span>&gt;</span>REMOTE<span class="hljs-tag">&lt;/<span class="hljs-name">type</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">address</span>&gt;</span>jms<span class="hljs-tag">&lt;/<span class="hljs-name">address</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">timeout</span>&gt;</span>5000<span class="hljs-tag">&lt;/<span class="hljs-name">timeout</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">grouping-handler</span>&gt;</span>
</code></pre>
<ul>
<li><p><code>type</code> 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&apos;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>
</li>
<li><p><code>address</code> 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>
</li>
<li><p><code>timeout</code> 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>
</li>
</ul>
<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>
<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>
<h2 id="clustered-grouping-best-practices">Clustered Grouping Best Practices</h2>
<p>Some best practices should be followed when using clustered grouping:</p>
<ol>
<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>
<h2 id="clustered-grouping-example">Clustered Grouping Example</h2>
<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>
</section>
</div>
<div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
</div>
</div>
</div>
<a href="exclusive-queues.html" class="navigation navigation-prev " aria-label="Previous page: Exclusive Queues">
<i class="fa fa-angle-left"></i>
</a>
<a href="consumer-priority.html" class="navigation navigation-next " aria-label="Next page: Consumer Priority">
<i class="fa fa-angle-right"></i>
</a>
</div>
<script>
var gitbook = gitbook || [];
gitbook.push(function() {
gitbook.page.hasChanged({"page":{"title":"Message Grouping","level":"1.43","depth":1,"next":{"title":"Consumer Priority","level":"1.44","depth":1,"path":"consumer-priority.md","ref":"consumer-priority.md","articles":[]},"previous":{"title":"Exclusive Queues","level":"1.42","depth":1,"path":"exclusive-queues.md","ref":"exclusive-queues.md","articles":[]},"dir":"ltr"},"config":{"plugins":[],"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"highlight":{},"search":{},"lunr":{"maxIndexSize":1000000},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"fontsettings":{"theme":"white","family":"sans","size":2},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"github":"apache/activemq-artemis","theme":"default","githubHost":"https://github.com/","pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"title":"ActiveMQ Artemis Documentation","links":{"home":"http://activemq.apache.org/artemis","issues":"https://issues.apache.org/jira/browse/ARTEMIS","contribute":"http://activemq.apache.org/contributing.html"},"gitbook":"3.x.x","description":"ActiveMQ Artemis User Guide and Reference Documentation"},"file":{"path":"message-grouping.md","mtime":"2020-03-31T18:40:48.000Z","type":"markdown"},"gitbook":{"version":"3.1.1","time":"2020-04-29T20:47:49.444Z"},"basePath":".","book":{"language":""}});
});
</script>
</div>
<script src="gitbook/gitbook.js"></script>
<script src="gitbook/theme.js"></script>
<script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
<script src="gitbook/gitbook-plugin-search/search.js"></script>
<script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
<script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
<script src="gitbook/gitbook-plugin-sharing/buttons.js"></script>
<script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
</body>
</html>