Chapter 8. Addresses, Queues, and Topics
AMQ Broker has a unique addressing model that is both powerful and flexible and that offers great performance. The addressing model comprises three main concepts: addresses, queues and routing types.
An address represents a messaging endpoint. Within the configuration, a typical address is given a unique name, 0 or more queues, and a routing type.
A queue is associated with an address. There can be multiple queues per address. Once an incoming message is matched to an address, the message is sent on to one or more of its queues, depending on the routing type configured. Queues can be configured to be automatically created and deleted.
A routing type determines how messages are sent to the queues associated with an address. A AMQ Broker address can be configured with two different routing types.
If you want your messages routed to… | Use this routing type … |
---|---|
A single queue within the matching address, in a point-to-point manner. | anycast |
Every queue within the matching address, in a publish-subscribe manner. | multicast |
An address must have at least one routing type.
It is possible to define more than one routing type per address, but this typically results in an anti-pattern and is therefore not recommended.
If an address does use both routing types, however, and the client does not show a preference for either one, the broker typically defaults to the anycast
routing type. The one exception is when the client uses the MQTT protocol. In that case, the default routing type is multicast
.
8.1. Configuring Point-to-Point Messaging
Point-to-point messaging is a common scenario in which a message sent by a producer has only one consumer. AMQP and JMS message producers and consumers can make use of point-to-point messaging queues, for example. Define an anycast
routing type for an address
so that its queues receive messages in a point-to-point manner.
When a message is received on an address using anycast
, AMQ Broker locates the queue associated with the address and routes the message to it. When consumers request to consume from the address, the broker locates the relevant queue and associates this queue with the appropriate consumers. If multiple consumers are connected to the same queue, messages are distributed amongst each consumer equally, providing the consumers are equally able to handle them.
Figure 8.1. Point-to-Point
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Wrap an
anycast
configuration element around the chosenqueue
element of anaddress
.<configuration ...> <core ...> ... <address name="address.foo"> <anycast> <queue name="q1"/> </anycast> </address> </core> </configuration>
8.2. Configuring Publish-Subscribe Messaging
In a publish-subscribe scenario, messages are sent to every consumer subscribed to an address. JMS topics and MQTT subscriptions are two examples of publish-subscribe messaging. An example of a publish-subscribe Assign a multicast
routing type for an address
so that its queues receive messages in a publish-subscribe manner.
When a message is received on an address with a multicast
routing type, AMQ Broker routes a copy of the message (in reality only a message reference to reduce the overhead of copying) to each queue.
Figure 8.2. Publish-Subscribe
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Add an empty
multicast
configuration element to the chosen address.<configuration ...> <core ...> ... <address name="topic.foo"> <multicast/> </address> </core> </configuration>
(Optional) Add one more
queue
elements to the address and wrap themulticast
element around them. This step is typically not needed since the broker automatically creates a queue for each subscription requested by a client.<configuration ...> <core ...> ... <address name="topic.foo"> <multicast> <queue name="client123.topic.foo"/> <queue name="client456.topic.foo"/> </multicast> </address> </core> </configuration>
8.3. Configuring a Point-to-Point Using Two Queues
It is actually possible to define more than one queue on an address with an anycast
routing type. When messages are received on such an address, they are distributed evenly across all the defined queues. Using Fully Qualified Queue Names described later, clients are able to select the queue that they’d like to subscribe to. Should more than one consumer connect direct to a single queue, AMQ Broker takes care of distributing messages between them, as in the example above.
Figure 8.3. Point-to-Point with Two Queues
This is how AMQ Broker handles load balancing of queues across multiple nodes in a cluster.
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Wrap an
anycast
configuration element around thequeue
elements in theaddress
.<configuration ...> <core ...> ... <address name="address.foo"> <anycast> <queue name="q1"/> <queue name="q2"/> </anycast> </address> </core> </configuration>
8.4. Using Point-to-Point and Publish-Subscribe Together
It is possible to define an address with both point-to-point and publish-subscribe semantics enabled. While not typically recommended, this can be useful when you want, for example, a JMS Queue named orders
and a JMS topic named orders
. The different routing types make the addresses appear to be distinct.
Using an example of JMS clients, the messages sent by a JMS queue producer are routed using the anycast
routing type. Messages sent by a JMS topic producer uses the multicast
routing type. In addition, when a JMS topic consumer attaches, it is attached to its own subscription queue. The JMS queue consumer, however, is attached to the anycast
queue.
Figure 8.4. Point-to-Point and Publish-Subscribe
The behavior in this scenario is dependent on the protocol being used. For JMS there is a clear distinction between topic and queue producers and consumers, which makes the logic straightforward. Other protocols like AMQP do not make this distinction. A message being sent via AMQP is routed by both anycast
and multicast
and consumers default to anycast
. For more information, check the behavior of each protocol in the sections on protocols.
The XML excerpt below is an example of what the configuration for an address using both anycast
and multicast
routing types would look like in BROKER_INSTANCE_DIR/etc/broker.xml
. Note that subscription queues are typically created on demand, so there is no need to list specific queue
elements inside the multicast
routing type.
<configuration ...> <core ...> ... <address name="foo.orders"> <anycast> <queue name="orders"/> </anycast> <multicast/> </address> </core> </configuration>
8.5. Configuring Subscription Queues
In most cases it is not necessary to pre-create subscription queues because protocol managers create subscription queues automatically when clients first request to subscribe to an address. See Protocol Managers and Addresses for more information. For durable subscriptions, the generated queue name is usually a concatenation of the client id and the address.
Configuring a Durable Subscription Queue
When an queue is configured as a durable subscription, the broker saves messages for any inactive subscribers and delivers them to the subscribers when they reconnect. Clients are therefore guaranteed to receive each message delivered to the queue after subscribing to it.
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Add the
durable
configuration element to the chosenqueue
and assign it a value oftrue
.<configuration ...> <core ...> ... <address name="durable.foo"> <multicast> <queue name="q1"> <durable>true</durable> </queue> </multicast> </address> </core> </configuration>
Configuring a Non-Shared Durable Subscription
The broker can be configured to prevent more than one consumer from connecting to a queue at any one time. The subscriptions to queues configured this way are therefore "non-shared".
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Add the
durable
configuration element to each chosen queue.<configuration ...> <core ...> ... <address name="non.shared.durable.foo"> <multicast> <queue name="orders1"> <durable>true</durable> </queue> <queue name="orders2"> <durable>true</durable> </queue> </multicast> </address> </core> </configuration>
Add the
max-consumers
attribute to each chosenqueue
element and assign it a value of1
.<configuration ...> <core ...> ... <address name="non.shared.durable.foo"> <multicast> <queue name="orders1" max-consumers="1"> <durable>true</durable> </queue> <queue name="orders2" max-consumers="1"> <durable>true</durable> </queue> </multicast> </address> </core> </configuration>
8.6. Using a Fully Qualified Queue Name
Internally the broker maps a client’s request for an address to specific queues. The broker decides on behalf of the client which queues to send messages, or from which queue to receive messages. However, more advanced use cases might require that the client specify a queue directly. In these situations the client can use a Fully Qualified Queue Name (FQQN), by specifying both the address name and the queue name, separated by a ::
.
Only message consumers can use FQQN. Do not use FQQN with message producers.
Prerequisites
An address is configured with two or more queues. In the example below the address
foo
has two queues,q1
andq2
.<configuration ...> <core ...> ... <addresses> <address name="foo"> <anycast> <queue name="q1" /> <queue name="q2" /> </anycast> </address> </addresses> </core> </configuration>
Procedure
In the client code, use both the address name and the queue name when requesting a connection from the broker. Remember to use two colons,
::
, to separate the names, as in the example Java code below.String FQQN = "foo::q1"; Queue q1 session.createQueue(FQQN); MessageConsumer consumer = session.createConsumer(q1);
8.7. Configuring Sharded Queues
A common pattern for processing of messages across a queue where only partial ordering is required is to use queue sharding. In AMQ Broker this can be achieved by creating an anycast
address that acts as a single logical queue, but which is backed by many underlying physical queues.
Procedure
Open
BROKER_INSTANCE_DIR/etc/broker.xml
and add anaddress
with the desired name. In the example below theaddress
namedsharded
is added to the configuration.<configuration ...> <core ...> ... <addresses> <address name="sharded"></address> </addresses> </core> </configuration>
Add the
anycast
routing type and include the desired number of sharded queues. In the example below, the queuesq1
,q2
, andq3
are added asanycast
destinations.<configuration ...> <core ...> ... <addresses> <address name="sharded"> <anycast> <queue name="q1" /> <queue name="q2" /> <queue name="q3" /> </anycast> </address> </addresses> </core> </configuration>
Using the configuration above, messages sent to sharded
are distributed equally across q1
, q2
and q3
. Clients are able to connect directly to a specific physical queue when using a fully qualified queue name and receive messages sent to that specific queue only.
To tie particular messages to a particular queue, clients can specify a message group for each message. The broker routes grouped messages to the same queue, and one consumer processes them all. See the chapter on Message Grouping for more information.
8.8. Limiting the Number of Consumers Connected to a Queue
You can limit the number of consumers connected to for a particular queue by using the max-consumers
attribute. Create an exclusive consumer by setting max-consumers
flag can be set to 1
. The default value is -1
, which is sets an unlimited number of consumers.
Procedure
Open
BROKER_INSTANCE_DIR/etc/broker.xml
and add themax-consumers
attribute to the desiredqueue
. In the example below, only20
consumers can connect to the queueq3
at the same time.<configuration ...> <core ...> ... <addresses> <address name="foo"> <anycast> <queue name="q3" max-consumers="20"/> </anycast> </address> </addresses> </core> </configuration>
(Optional) Create an exclusive consumer by setting
max-consumers
to1
, as in the example below.<configuration ...> <core ...> ... <address name="foo"> <anycast> <queue name="q3" max-consumers="1"/> </anycast> </address> </core> </configuration>
(Optional) Have an unlimited number of consumers by setting
max-consumers
to-1
, as in the example below.<configuration ...> <core ...> ... <address name="foo"> <anycast> <queue name="q3" max-consumers="-1"/> </anycast> </address> </core> </configuration>
8.9. Configuring a Prefix to Connect to a Specific Routing Type
Normally, if a message is received by an address that uses both anycast
and multicast
, one of the anycast
queues receive the message and all of the multicast
queues. However, clients can specify a special prefix when connecting to an address to specify whether to connect using anycast
or multicast
. The prefixes are custom values that are designated using the anycastPrefix
and multicastPrefix
parameters within the URL of an acceptor
.
Configuring an Anycast Prefix
-
In
BROKER_INSTANCE_DIR/etc/broker.xml
, add theanycastPrefix
to the URL of the desiredacceptor
. In the example below, theacceptor
is configured to useanycast://
for theanycastPrefix
. Client code can specifyanycast://foo/
if the client needs to send a message to only one of the anycast queues.
<configuration ...> <core ...> ... <acceptors> <!-- Acceptor for every supported protocol --> <acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP&anycastPrefix=anycast://</acceptor> </acceptors> ... </core> </configuration>
Configuring a Multicast Prefix
-
In
BROKER_INSTANCE_DIR/etc/broker.xml
, add theanycastPrefix
to the URL of the desiredacceptor
. In the example below, theacceptor
is configured to usemulticast://
for themulticastPrefix
. Client code can specifymulticast://foo/
if the client needs the message sent to only the multicast queues of the address.
<configuration ...> <core ...> ... <acceptors> <!-- Acceptor for every supported protocol --> <acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP&multicastPrefix=multicast://</acceptor> </acceptors> ... </core> </configuration>
8.10. Protocol Managers and Addresses
A protocol manager maps protocol-specific concepts down to the AMQ Broker address model concepts: queues and routing types. For example, when a client sends a MQTT subscription packet with the addresses /house/room1/lights
and /house/room2/lights
, the MQTT protocol manager understands that the two addresses require multicast
semantics. The protocol manager therefore first looks to ensure that multicast
is enabled for both addresses. If not, it attempts to dynamically create them. If successful, the protocol manager then creates special subscription queues for each subscription requested by the client.
Each protocol behaves slightly differently. The table below describes what typically happens when subscribe frames to various types of queue
are requested.
If the queue is of this type… | The typical action for a protocol manager is to… |
---|---|
Durable Subscription Queue |
Look for the appropriate address and ensures that The special name allows the protocol manager to quickly identify the required client subscription queues should the client disconnect and reconnect at a later date. When the client unsubscribes the queue is deleted. |
Temporary Subscription Queue |
Look for the appropriate address and ensures that When the client disconnects the queue is deleted. |
Point-to-Point Queue |
Look for the appropriate address and ensures that If the queue is auto created, it is automatically deleted once there are no consumers and no messages in it. |
8.11. Configuring Address Settings
AMQ Broker has several configurable options that control aspects of how and when a message is delivered, how many attempts should be made, and when the message expires. These configuration options all exist within the <address-setting>
configuration element. You can have AMQ Broker apply a single <address-setting>
to multiple destinations by using a wildcard syntax.
AMQ Broker Wildcard Syntax
AMQ Broker uses a specific syntax for representing wildcards in security settings, address settings, and when creating consumers.
- A wildcard expression contains words delimited by the character ‘.’.
- The special characters ‘#’ and ‘*’ also have special meaning and can take the place of a word.
- The character ‘#’ means 'match any sequence of zero or more words'. Use this at the end of your expression.
- The character ‘*’ means 'match a single word'. Use this anywhere within your expression.
Matching is not done character by character, but at each delimiter boundary. For example, an address-setting
looking to match queues using my
in their name would not match with a queue named myqueue
.
When more than one address-setting
matches a queue, the broker will overlay configurations, using the configuration of the least specific match as the baseline. Literal expressions are more specific than wildcards, and *
is more specific than #
. For example, both my.queue
and my.*
match the queue my.queue
. In this case, the broker first applies the configuration found under my.*
, since a wildcard expression is less specific than a literal. Next, the broker overlays the configuration of the my.queue
address-setting
, which will overwrite any configuration shared with my.*
. Given the configuration below, the queue my.queue
would have max-delivery-attempts
set to 3
and last-value-queue
set to false
.
<address-setting match="my.*"> <max-delivery-attempts>3</max-delivery-attempts> <last-value-queue>true</last-value-queue> </address-setting> <address-setting match="my.queue"> <last-value-queue>false</last-value-queue> </address-setting>
The examples in the table below illustrate how wildcards are used to match a set of addresses.
Example | Description |
---|---|
# |
The default |
news.europe.# |
Matches |
news.* |
Matches |
news.*.sport |
Matches |
Configuring Wildcard Syntax
You can customize the syntax used for wildcard addresses by adding configuration to broker.xml
.
Procedure
-
Edit
broker.xml
by adding a<wildcard-addresses>
section to the configuration, as in the example below.
<configuration> <core> ... <wildcard-addresses> 1 <enabled>true</enabled> 2 <delimiter>,</delimiter> 3 <any-words>@</any-words> 4 <single-word>$</single-word> 5 </wildcard-addresses> ... </core> </configuration>
- 1
- Add
wildcard-addresses
beneath thecore
configuration element. - 2
- Set
enabled
totrue
to tell the broker to use your custom settings. - 3
- Provide a custom character to use as the
delimiter
instead of the default, which is.
. - 4
- The character provided as the value for
any-words
is used to mean 'match any sequence of zero or more words' and will replace the default#
. Use this character at the end of your expression. - 5
- The character provided as the value for
single-word
is used to mean 'match a single word' and will replaced the default*
. Use this character anywhere within your expression.
8.12. Creating and Deleting Queues and Addresses Automatically
You can configure AMQ Broker to automatically create addresses and queues, and to delete them after they are no longer in use. This saves you from having to pre-configure each address before a client can connect to it.
Automatic creation and deletion of queues and addresses is configured on a per address-setting
basis. The configuration is applied to any address or queue that is a match for the address-setting
. See Configuring Address Settings for more information about how to use wildcard syntax to match addresses and queues to an address-setting
.
The table below lists the configuration elements available when configuring an address-setting
to automatically create and delete its queues and addresses.
If you want the address-setting to… | Add this configuration… |
---|---|
Create addresses when a client sends a message to or attempts to consume a message from a queue mapped to an address that doesn’t exist. |
|
Create a queue when a client sends a message to or attempts to consume a message from a queue. |
|
Delete an automatically-created address when it no longer has any queues. |
|
Delete an automatically-created queue when the queue has 0 consumers and 0 messages. |
|
Use a specific routing type if the client does not specify one. |
|
Procedure
Edit the file BROKER_INSTANCE_DIR/etc/broker.xml
and configure an address-setting
for automatic creation and deletion. The example below uses all of the configuration elements mentioned in the table above.
<configuration ...> <core ...> ... <address-settings> <address-setting match="/news/politics/#"> 1 <auto-create-addresses>true</auto-create-addresses> 2 <auto-delete-addresses>true</auto-delete-addresses> 3 <auto-create-queues>true</auto-create-queues> 4 <auto-delete-queues>true</auto-delete-queues> 5 <default-address-routing-type>ANYCAST</default-address-routing-type> 6 </address-setting> </address-settings> ... </core> </configuration>
- 1
- The configuration included in this
address-setting
is applied to any address or queue that matches the wildcard/news/politics/#
. For more information on using wildcard syntax see AMQ Broker Widcard Syntax. - 2
- The broker creates an address that does not exist when a client requests it.
- 3
- An automatically-created address is deleted when it no longer has any queues associated with it.
- 4
- The broker creates a queue that does not exist when a client requests it.
- 5
- An automatically-created queue is deleted when it no longer has any consumers or messages.
- 6
- If the client does not specify a routing type when connecting, the broker uses
ANYCAST
when delivering messages to an address. The default value isMULTICAST
. See the introduction of this chapter for more information about routing types.