blob: 930e461198e982f9579e098f4a76431f3823c64a [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="pre-acknowledge.html" />
<link rel="prev" href="last-value-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="messaging-concepts.html">
<a href="messaging-concepts.html">
Messaging Concepts
</a>
</li>
<li class="chapter " data-level="1.6" data-path="architecture.html">
<a href="architecture.html">
Architecture
</a>
</li>
<li class="chapter " data-level="1.7" data-path="using-server.html">
<a href="using-server.html">
Using the Server
</a>
</li>
<li class="chapter " data-level="1.8" data-path="address-model.html">
<a href="address-model.html">
Address Model
</a>
</li>
<li class="chapter " data-level="1.9" data-path="using-jms.html">
<a href="using-jms.html">
Using JMS
</a>
</li>
<li class="chapter " data-level="1.10" data-path="using-core.html">
<a href="using-core.html">
Using Core
</a>
</li>
<li class="chapter " data-level="1.11" data-path="using-AMQP.html">
<a href="using-AMQP.html">
Using AMQP
</a>
</li>
<li class="chapter " data-level="1.12" 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.13" data-path="client-classpath.html">
<a href="client-classpath.html">
The Client Classpath
</a>
</li>
<li class="chapter " data-level="1.14" data-path="examples.html">
<a href="examples.html">
Examples
</a>
</li>
<li class="chapter " data-level="1.15" data-path="wildcard-routing.html">
<a href="wildcard-routing.html">
Routing Messages With Wild Cards
</a>
</li>
<li class="chapter " data-level="1.16" data-path="wildcard-syntax.html">
<a href="wildcard-syntax.html">
Understanding the Apache ActiveMQ Artemis Wildcard Syntax
</a>
</li>
<li class="chapter " data-level="1.17" data-path="filter-expressions.html">
<a href="filter-expressions.html">
Filter Expressions
</a>
</li>
<li class="chapter " data-level="1.18" data-path="persistence.html">
<a href="persistence.html">
Persistence
</a>
</li>
<li class="chapter " data-level="1.19" data-path="configuring-transports.html">
<a href="configuring-transports.html">
Configuring Transports
</a>
</li>
<li class="chapter " data-level="1.20" data-path="config-reload.html">
<a href="config-reload.html">
Configuration Reload
</a>
</li>
<li class="chapter " data-level="1.21" data-path="connection-ttl.html">
<a href="connection-ttl.html">
Detecting Dead Connections
</a>
</li>
<li class="chapter " data-level="1.22" data-path="slow-consumers.html">
<a href="slow-consumers.html">
Detecting Slow Consumers
</a>
</li>
<li class="chapter " data-level="1.23" data-path="network-isolation.html">
<a href="network-isolation.html">
Avoiding Network Isolation
</a>
</li>
<li class="chapter " data-level="1.24" data-path="transaction-config.html">
<a href="transaction-config.html">
Resource Manager Configuration
</a>
</li>
<li class="chapter " data-level="1.25" data-path="flow-control.html">
<a href="flow-control.html">
Flow Control
</a>
</li>
<li class="chapter " data-level="1.26" data-path="send-guarantees.html">
<a href="send-guarantees.html">
Guarantees of sends and commits
</a>
</li>
<li class="chapter " data-level="1.27" data-path="undelivered-messages.html">
<a href="undelivered-messages.html">
Message Redelivery and Undelivered Messages
</a>
</li>
<li class="chapter " data-level="1.28" data-path="message-expiry.html">
<a href="message-expiry.html">
Message Expiry
</a>
</li>
<li class="chapter " data-level="1.29" data-path="large-messages.html">
<a href="large-messages.html">
Large Messages
</a>
</li>
<li class="chapter " data-level="1.30" data-path="paging.html">
<a href="paging.html">
Paging
</a>
</li>
<li class="chapter " data-level="1.31" data-path="queue-attributes.html">
<a href="queue-attributes.html">
Queue Attributes
</a>
</li>
<li class="chapter " data-level="1.32" data-path="scheduled-messages.html">
<a href="scheduled-messages.html">
Scheduled Messages
</a>
</li>
<li class="chapter " data-level="1.33" data-path="last-value-queues.html">
<a href="last-value-queues.html">
Last-Value Queues
</a>
</li>
<li class="chapter active" data-level="1.34" data-path="message-grouping.html">
<a href="message-grouping.html">
Message Grouping
</a>
</li>
<li class="chapter " data-level="1.35" data-path="pre-acknowledge.html">
<a href="pre-acknowledge.html">
Extra Acknowledge Modes
</a>
</li>
<li class="chapter " data-level="1.36" data-path="management.html">
<a href="management.html">
Management
</a>
</li>
<li class="chapter " data-level="1.37" data-path="security.html">
<a href="security.html">
Security
</a>
</li>
<li class="chapter " data-level="1.38" data-path="broker-plugins.html">
<a href="broker-plugins.html">
Broker Plugins
</a>
</li>
<li class="chapter " data-level="1.39" data-path="resource-limits.html">
<a href="resource-limits.html">
Resource Limits
</a>
</li>
<li class="chapter " data-level="1.40" data-path="jms-bridge.html">
<a href="jms-bridge.html">
The JMS Bridge
</a>
</li>
<li class="chapter " data-level="1.41" data-path="client-reconnection.html">
<a href="client-reconnection.html">
Client Reconnection and Session Reattachment
</a>
</li>
<li class="chapter " data-level="1.42" data-path="diverts.html">
<a href="diverts.html">
Diverting and Splitting Message Flows
</a>
</li>
<li class="chapter " data-level="1.43" data-path="core-bridges.html">
<a href="core-bridges.html">
Core Bridges
</a>
</li>
<li class="chapter " data-level="1.44" data-path="duplicate-detection.html">
<a href="duplicate-detection.html">
Duplicate Message Detection
</a>
</li>
<li class="chapter " data-level="1.45" data-path="clusters.html">
<a href="clusters.html">
Clusters
</a>
</li>
<li class="chapter " data-level="1.46" data-path="ha.html">
<a href="ha.html">
High Availability and Failover
</a>
</li>
<li class="chapter " data-level="1.47" data-path="graceful-shutdown.html">
<a href="graceful-shutdown.html">
Graceful Server Shutdown
</a>
</li>
<li class="chapter " data-level="1.48" data-path="libaio.html">
<a href="libaio.html">
Libaio Native Libraries
</a>
</li>
<li class="chapter " data-level="1.49" data-path="thread-pooling.html">
<a href="thread-pooling.html">
Thread management
</a>
</li>
<li class="chapter " data-level="1.50" data-path="logging.html">
<a href="logging.html">
Logging
</a>
</li>
<li class="chapter " data-level="1.51" data-path="rest.html">
<a href="rest.html">
REST Interface
</a>
</li>
<li class="chapter " data-level="1.52" data-path="embedding-activemq.html">
<a href="embedding-activemq.html">
Embedding Apache ActiveMQ Artemis
</a>
</li>
<li class="chapter " data-level="1.53" data-path="karaf.html">
<a href="karaf.html">
Apache Karaf
</a>
</li>
<li class="chapter " data-level="1.54" data-path="spring-integration.html">
<a href="spring-integration.html">
Spring Integration
</a>
</li>
<li class="chapter " data-level="1.55" data-path="cdi-integration.html">
<a href="cdi-integration.html">
CDI Integration
</a>
</li>
<li class="chapter " data-level="1.56" data-path="intercepting-operations.html">
<a href="intercepting-operations.html">
Intercepting Operations
</a>
</li>
<li class="chapter " data-level="1.57" data-path="protocols-interoperability.html">
<a href="protocols-interoperability.html">
Protocols and Interoperability
</a>
</li>
<li class="chapter " data-level="1.58" data-path="tools.html">
<a href="tools.html">
Tools
</a>
</li>
<li class="chapter " data-level="1.59" data-path="maven-plugin.html">
<a href="maven-plugin.html">
Maven Plugin
</a>
</li>
<li class="chapter " data-level="1.60" data-path="unit-testing.html">
<a href="unit-testing.html">
Unit Testing
</a>
</li>
<li class="chapter " data-level="1.61" data-path="perf-tuning.html">
<a href="perf-tuning.html">
Troubleshooting and Performance Tuning
</a>
</li>
<li class="chapter " data-level="1.62" data-path="configuration-index.html">
<a href="configuration-index.html">
Configuration Reference
</a>
</li>
<li class="chapter " data-level="1.63" data-path="updating-artemis.html">
<a href="updating-artemis.html">
Updating Artemis
</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> // send 2 messages in the same group to ensure the same
// consumer will receive both
Message message = ...
message.setStringProperty(&quot;JMSXGroupID&quot;, &quot;Group-0&quot;);
producer.send(message);
message = ...
message.setStringProperty(&quot;JMSXGroupID&quot;, &quot;Group-0&quot;);
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>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>java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
connectionFactory.myConnectionFactory=tcp://localhost:61616?roupID=Group-0
</code></pre><h2 id="example">Example</h2>
<p>See the [examples](examples.md} chapter for an example 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>There are 2 types of handlers; Local and Remote. Each cluster should
choose 1 node to have a local grouping handler and all the other nodes
should have remote handlers- it&apos;s the local handler that actually makes
the decision as to what route should be used, all the other remote
handlers converse with this. Here is a sample config for both types of
handler, this should be configured in the <em>broker.xml</em>
file.</p>
<pre><code>&lt;grouping-handler name=&quot;my-grouping-handler&quot;&gt;
&lt;type&gt;LOCAL&lt;/type&gt;
&lt;address&gt;jms&lt;/address&gt;
&lt;timeout&gt;5000&lt;/timeout&gt;
&lt;/grouping-handler&gt;
&lt;grouping-handler name=&quot;my-grouping-handler&quot;&gt;
&lt;type&gt;REMOTE&lt;/type&gt;
&lt;address&gt;jms&lt;/address&gt;
&lt;timeout&gt;5000&lt;/timeout&gt;
&lt;/grouping-handler&gt;
</code></pre><p>The <em>address</em> attribute refers to a <a href="#clusters.address">cluster connection and the address
it uses</a>, refer to the clustering section on how to
configure clusters. The <em>timeout</em> attribute referees to 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>
<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">examples</a> chapter for an example of 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="last-value-queues.html" class="navigation navigation-prev " aria-label="Previous page: Last-Value Queues">
<i class="fa fa-angle-left"></i>
</a>
<a href="pre-acknowledge.html" class="navigation navigation-next " aria-label="Next page: Extra Acknowledge Modes">
<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.34","depth":1,"next":{"title":"Extra Acknowledge Modes","level":"1.35","depth":1,"path":"pre-acknowledge.md","ref":"pre-acknowledge.md","articles":[]},"previous":{"title":"Last-Value Queues","level":"1.33","depth":1,"path":"last-value-queues.md","ref":"last-value-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/","issues":"http://activemq.apache.org/","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":"2017-08-02T14:45:43.000Z","type":"markdown"},"gitbook":{"version":"3.1.1","time":"2017-08-04T18:56:43.143Z"},"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>