JBoss.orgCommunity Documentation

Chapter 28. Message Grouping

28.1. Using Core API
28.2. Using JMS
28.3. Example
28.4. Example
28.5. Clustered Grouping
28.5.1. Clustered Grouping Best Practices
28.5.2. Clustered Grouping Example

Message groups are sets of messages that have the following characteristics:

Message groups are useful when you want all messages for a certain value of the property to be processed serially by the same consumer.

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 _HQ_GROUP_ID property.

This will ensure that all messages for a particular stock will always be processed by the same consumer.

The property name used to identify the message group is "_HQ_GROUP_ID" (or the constant MessageImpl.HDR_GROUP_ID). Alternatively, you can set autogroup to true on the SessionFactory which will pick a random unique id.

The property name used to identify the message group is JMSXGroupID.

 // send 2 messages in the same group to ensure the same
 // consumer will receive both
 Message message = ...
 message.setStringProperty("JMSXGroupID", "Group-0");
 producer.send(message);

 message = ...
 message.setStringProperty("JMSXGroupID", "Group-0");
 producer.send(message);          
       

Alternatively, you can set autogroup to true on the HornetQConnectonFactory which will pick a random unique id. This can also be set in the hornetq-jms.xml file like this:

<connection-factory name="ConnectionFactory">
      <connectors>
         <connector-ref connector-name="netty-connector"/>
      </connectors>
      <entries>
         <entry name="ConnectionFactory"/>
      </entries>
      <autogroup>true</autogroup>
</connection-factory>

Alternatively you can set the group id via the connection factory. All messages sent with producers created via this connection factory will set the JMSXGroupID to the specified value on all messages sent. To configure the group id set it on the connection factory in the hornetq-jms.xml config file as follows

         <connection-factory name="ConnectionFactory">
      <connectors>
         <connector-ref connector-name="netty-connector"/>
      </connectors>
      <entries>
         <entry name="ConnectionFactory"/>
      </entries>
      <group-id>Group-0</group-id>
   </connection-factory>
      

See Section 11.1.34, “Message Group” for an example which shows how message groups are configured and used with JMS.

See Section 11.1.35, “Message Group” for an example which shows how message groups are configured via a connection factory.

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'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.

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.

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's the local handler that actually makes the decsion 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 hornetq-configuration.xml file.

   <grouping-handler name="my-grouping-handler">
      <type>LOCAL</type>
      <address>jms</address>
      <timeout>5000</timeout>
   </grouping-handler>

   <grouping-handler name="my-grouping-handler">
      <type>REMOTE</type>
      <address>jms</address>
      <timeout>5000</timeout>
   </grouping-handler>

The address attribute refers to a cluster connection and the address it uses, refer to the clustering section on how to configure clusters. The timeout attribute referes 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.

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.

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.

See Section 11.1.8, “Clustered Grouping” for an example of how to configure message groups with a HornetQ cluster