540 lines
18 KiB
Markdown
540 lines
18 KiB
Markdown
# Address Model
|
||
|
||
Every messaging protocol and API that Apache ActiveMQ Artemis supports defines
|
||
a different set of messaging resources.
|
||
|
||
- JMS uses _queues_ and _topics_
|
||
- STOMP uses generic _destinations_
|
||
- MQTT uses _topics_
|
||
- AMQP uses generic _nodes_
|
||
|
||
In order to deal the the unique semantics and use-cases for each of these the
|
||
broker has a flexible and powerful address model based on the following _core_
|
||
set of resources:
|
||
|
||
- **address**
|
||
- **queue**
|
||
- **routing type**
|
||
|
||
### Address
|
||
|
||
Messages are *sent* to an address. An address is given a unique name, a routing
|
||
type, and zero or more queues.
|
||
|
||
### Queue
|
||
|
||
Messages are *consumed* from a queue. A queue is bound to an address. It is
|
||
given a unique name and a routing type. There can be zero or more queues bound
|
||
to one address. When a message is sent to an address it is routed to one or
|
||
more of its queues based on the configured routing type.
|
||
|
||
The name of the queue must be _globally_ unique. For example, you can't have a
|
||
queue named `q1` on address `a1` and also a queue named `q1` address `a2`.
|
||
|
||
### Routing Type
|
||
|
||
A routing type determines how messages are routed from an address to the
|
||
queue(s) bound to that address. Two different routing types are supported,
|
||
**anycast** and **multicast**.
|
||
|
||
If you want your messages routed to...|Use this routing type...
|
||
---|---
|
||
a single anycast queue on the address.|anycast
|
||
every multicast queue on the address.|multicast
|
||
|
||
> **Note:**
|
||
>
|
||
> It is possible to define queues with a different routing type for the same
|
||
> address, but this typically results in an anti-pattern and is therefore not
|
||
> recommended.
|
||
|
||
## Automatic Configuration
|
||
|
||
By default Apache ActiveMQ Artemis will automatically create addresses and
|
||
queues to support the semantics of whatever protocol you're using. The broker
|
||
understands how to support each protocol's functionality with the core
|
||
resources so that in most cases no manual configuration is required. This saves
|
||
you from having to preconfigure each address and queue before a client can
|
||
connect to it.
|
||
|
||
The broker can optionally be configured to automatically delete addresses and
|
||
queues when they are no longer in use.
|
||
|
||
Automatic creation and deletion is configured on a per address basis and is
|
||
controlled by the following [`address-setting`](address-settings.md) elements:
|
||
|
||
- `auto-create-addresses`
|
||
- `auto-delete-addresses`
|
||
- `default-address-routing-type`
|
||
- `auto-create-queues`
|
||
- `auto-delete-queues`
|
||
- `default-queue-routing-type`
|
||
|
||
See [the documentation on address settings](address-settings.md) for more
|
||
details on these elements.
|
||
|
||
Of course, automatic configuration can be disabled and everything can be
|
||
configured manually. Read on for more details about manual configuration.
|
||
|
||
## Basic Manual Configuration
|
||
|
||
The following examples show how to configure resources for basic anycast and
|
||
multicast use-cases.
|
||
|
||
> **Note:**
|
||
>
|
||
> Many of the details of these use-cases are protocol agnostic. The goal here
|
||
> is to demonstrate and explain the basic configuration elements and how the
|
||
> address model works fundamentally.
|
||
|
||
### Anycast
|
||
|
||
The most common use-case for anycast semantics, sometimes referred to as
|
||
[point-to-point](messaging-concepts.md#point-to-point), involves applications
|
||
following a "competing consumer" pattern to receive messages from a shared
|
||
queue. The more consumers receiving messages the greater the overall message
|
||
throughput. Multiple Java applications sharing a JMS queue is a classic example
|
||
of this use-case.
|
||
|
||
In this use-case the broker is configured, for example, with an address,
|
||
`anycast.foo` using the `anycast` routing type with just one queue, `q1`. When
|
||
a producer sends a message to `address.foo` it is then routed to `q1` and
|
||
finally dispatched to one of the consumers.
|
||
|
||
![Anycast](images/anycast.png)
|
||
Figure 1. Anycast
|
||
|
||
This is what the configuration for this use-case would look like in
|
||
`etc/broker.xml`:
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="address.foo">
|
||
<anycast>
|
||
<queue name="q1"/>
|
||
</anycast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
For most protocols and APIs which support this kind of use-case (e.g. JMS,
|
||
AMQP, etc.) it is customary to use the _same name_ when sending and consuming
|
||
messages. In that case you'd use a configuration like this:
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="orderQueue">
|
||
<anycast>
|
||
<queue name="orderQueue"/>
|
||
</anycast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
### Multicast
|
||
|
||
The most common use-case for multicast semantics, sometimes referred to as
|
||
[publish/subscribe](messaging-concepts.md#publish-subscribe) or "pub/sub",
|
||
involves each application receiving every message sent to an address. Multiple
|
||
applications consuming from a JMS topic is a classic example of this use-case.
|
||
MQTT subscriptions is another supported example of multicast semantics.
|
||
|
||
In this use-case the broker is configured with an address, `address.foo` using
|
||
the `multicast` routing type with two queues, `q1` & `q2`. When a producer
|
||
sends a message to `address.foo` it is then routed to *both* `q1` & `q2` so
|
||
that ultimately both consumers receive the same messages.
|
||
|
||
![Multicast](images/multicast.png)
|
||
Figure 2. Multicast
|
||
|
||
This is what the configuration for this use-case would look like in
|
||
`etc/broker.xml`:
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="address.foo">
|
||
<multicast>
|
||
<queue name="q1"/>
|
||
<queue name="q2"/>
|
||
</multicast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
This basic configuration is simple and straight-forward, but there's a
|
||
problem. In a normal pub/sub use-case like with a JMS topic or with MQTT the
|
||
number of subscribers *isn't known ahead of time*. In that case, this is the
|
||
recommended configuration:
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="address.foo">
|
||
<multicast/>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
Define `<multicast/>` with no queues and the broker will automatically create
|
||
queues for each subscription when the consumers connect to `address.foo`. Then
|
||
when a message is sent to `address.foo` it will be routed to each queue for
|
||
each subscriber and therefore each subscriber will get every message. These
|
||
queues are often referred to as _subscription queues_ for obvious reasons.
|
||
|
||
These subscription queues are typically named based on the semantics of the
|
||
protocol used to create them. For example, JMS supports durable and non-durable
|
||
subscriptions. The queue for a non-durable subscription is named with a UUID,
|
||
but the queue used for a durable subscription is named according to the JMS
|
||
"client ID" and "subscription name." Similar conventions are used for AMQP,
|
||
MQTT, STOMP, etc.
|
||
|
||
## Advanced Manual Configuration
|
||
|
||
### Fully Qualified Queue Names
|
||
|
||
In most cases it’s not necessary or desirable to statically configure the
|
||
aforementioned subscription queues. However, there are scenarios where a user
|
||
may want to statically configure a subscription queue and later connect to that
|
||
queue directly using a **Fully Qualified Queue Name** (FQQN).
|
||
|
||
An FQQN uses a special syntax to specify *both* the address and the queue so
|
||
that applications using protocols and APIs which don't natively understand the
|
||
address/queue separation (e.g. AMQP, JMS, etc.) can send messages or subscribe
|
||
*directly* to a queue rather than being limited to the address. Applications
|
||
simply need to use the address name and the queue name separated by `::` (e.g.
|
||
`address::queue`).
|
||
|
||
In this example, the address `a1` is configured with two queues: `q1`, `q2` as
|
||
shown in the configuration below.
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="a1">
|
||
<multicast>
|
||
<queue name="q1" />
|
||
<queue name="q2" />
|
||
</multicast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
Here's a snippet of Java code using JMS which demonstrates the FQQN syntax:
|
||
|
||
```java
|
||
Queue q1 session.createQueue("a1::q1");
|
||
MessageConsumer consumer = session.createConsumer(q1);
|
||
```
|
||
|
||
> **Note**
|
||
>
|
||
> The string `::` should only be used for FQQN and not in any other context in
|
||
> address or queue names.
|
||
|
||
The examples below show how to use broker side configuration to statically
|
||
configure a queue with publish subscribe behavior for shared, non-shared,
|
||
durable and non-durable subscription behavior.
|
||
|
||
#### Shared, Durable Subscription Queue using `max-consumers`
|
||
|
||
The default behavior for queues is to not limit the number connected queue
|
||
consumers. The `max-consumers` parameter of the queue element can be used to
|
||
limit the number of connected consumers allowed at any one time.
|
||
|
||
Open the file `etc/broker.xml` for editing.
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="durable.foo">
|
||
<multicast>
|
||
<!-- pre-configured shared durable subscription queue -->
|
||
<queue name="q1" max-consumers="10">
|
||
<durable>true</durable>
|
||
</queue>
|
||
</multicast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
#### Non-shared, Durable Subscription Queue
|
||
|
||
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". To do this simply set the `max-consumers` parameter to
|
||
`1`:
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="durable.foo">
|
||
<multicast>
|
||
<!-- pre-configured non shared durable subscription queue -->
|
||
<queue name="q1" max-consumers="1">
|
||
<durable>true</durable>
|
||
</queue>
|
||
</multicast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
#### Non-durable Subscription Queue
|
||
|
||
Non-durable subscriptions are again usually managed by the relevant protocol
|
||
manager, by creating and deleting temporary queues.
|
||
|
||
If a user requires to pre-create a queue that behaves like a non-durable
|
||
subscription queue the `purge-on-no-consumers` flag can be enabled on the
|
||
queue. When `purge-on-no-consumers` is set to `true`. The queue will not
|
||
start receiving messages until a consumer is attached. When the last consumer
|
||
is detached from the queue. The queue is purged (its messages are removed)
|
||
and will not receive any more messages until a new consumer is attached.
|
||
|
||
Open the file `etc/broker.xml` for editing.
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="non.shared.durable.foo">
|
||
<multicast>
|
||
<queue name="orders1" purge-on-no-consumers="true"/>
|
||
</multicast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
### Disabled Queue
|
||
|
||
If a user requires to statically configure a queue and disable routing to it,
|
||
for example where a queue needs to be defined so a consumer can bind, but you
|
||
want to disable message routing to it for the time being.
|
||
|
||
Or you need to stop message flow to the queue to allow investigation keeping
|
||
the consumer bound, but don't wish to have further messages routed to the queue
|
||
to avoid message build up.
|
||
|
||
When `enabled` is set to `true` the queue will have messages routed to it.
|
||
(default)
|
||
|
||
When `enabled` is set to `false` the queue will NOT have messages routed to it.
|
||
|
||
Open the file `etc/broker.xml` for editing.
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="foo.bar">
|
||
<multicast>
|
||
<queue name="orders1" enabled="false"/>
|
||
</multicast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
> **Warning:**
|
||
>
|
||
> Disabling all the queues on an address means that any message sent to that
|
||
> address will be silently dropped.
|
||
|
||
### Temporary Queues
|
||
|
||
For some protocols and APIs which only support monolithic "destinations"
|
||
without the address/queue separation (e.g. AMQP, JMS, etc.) temporary queues
|
||
are created by the broker using a UUID (i.e universally unique identifier) as
|
||
the name for both the address and the queue. Because the name is a UUID it is
|
||
impossible to create an `address-setting` for it whose `match` is anything but
|
||
`#`.
|
||
|
||
To solve this problem one can specify the `temporary-queue-namespace` in
|
||
`broker.xml` and then create an `address-setting` whose `match` value
|
||
corresponds to the configured `temporary-queue-namespace`. When the
|
||
`temporary-queue-namespace` is set and a temporary queue is created then the
|
||
broker will prepend the `temporary-queue-namespace` value along with the
|
||
`delimiter` value configured in `wildcard-addresses` (defaults to `.`) to the
|
||
address name and use that to lookup the associated `address-setting` values.
|
||
|
||
Here's a simple example configuration:
|
||
|
||
```xml
|
||
<temporary-queue-namespace>temp</temporary-queue-namespace>
|
||
|
||
<address-settings>
|
||
<address-setting match="temp.#">
|
||
<enable-metrics>false</enable-metrics>
|
||
</address-setting>
|
||
</address-settings>
|
||
```
|
||
|
||
Using this configuration any temporary queue will have metrics disabled.
|
||
|
||
> **Note:**
|
||
>
|
||
> This setting does *not* change the actual name of the temporary queue. It
|
||
> only changes the name used to *lookup* the address-settings.
|
||
|
||
### Other Advanced Configurations
|
||
|
||
Each of the following advanced configurations have their own chapter so their
|
||
details are not repeated here:
|
||
|
||
- [Exclusive queues](exclusive-queues.md)
|
||
- [Last Value queues](last-value-queues.md)
|
||
- [Non-Destructive queues](non-destructive-queues.md)
|
||
- [Ring queues](ring-queues.md)
|
||
- [Retroactive addresses](retroactive-addresses.md)
|
||
|
||
## How to filter messages
|
||
|
||
Apache ActiveMQ Artemis supports the ability to filter messages using [Filter
|
||
Expressions](filter-expressions.md).
|
||
|
||
Filters can be applied in two places - on a queue and on a consumer.
|
||
|
||
Filtering messages on a queue increases performance vs. filtering on the
|
||
consumer because the messages don't need to be scanned. However, a queue filter
|
||
is often not as flexible.
|
||
|
||
### Queue Filter
|
||
|
||
When a filter is applied to a queue, messages are filtered _before_ they are
|
||
routed to the queue. To add a filter use the `filter` element when configuring
|
||
a queue, e.g.:
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="filter">
|
||
<anycast>
|
||
<queue name="filter">
|
||
<filter string="color='red'"/>
|
||
</queue>
|
||
</anycast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
|
||
The filter defined above ensures that only messages with an attribute
|
||
`"color='red'"` is sent to this queue.
|
||
|
||
### Consumer Filters
|
||
|
||
Consumer filters are applied _after_ messages have routed to the queue and are
|
||
defined using the appropriate client APIs. The following JMS example shows how
|
||
consumer filters work.
|
||
|
||
Define an address with a single queue, with no filter applied in
|
||
`etc/broker.xml`.
|
||
|
||
```xml
|
||
<addresses>
|
||
<address name="filter">
|
||
<anycast>
|
||
<queue name="filter"/>
|
||
</anycast>
|
||
</address>
|
||
</addresses>
|
||
```
|
||
Then send some messages to the queue.
|
||
```java
|
||
...
|
||
// Send some messages
|
||
for (int i = 0; i < 3; i ++) {
|
||
TextMessage redMessage = senderSession.createTextMessage("Red");
|
||
redMessage.setStringProperty("color", "red");
|
||
producer.send(redMessage)
|
||
|
||
TextMessage greenMessage = senderSession.createTextMessage("Green");
|
||
greenMessage.setStringProperty("color", "green");
|
||
producer.send(greenMessage)
|
||
}
|
||
```
|
||
|
||
At this point the queue would have 6 messages: red, green, red, green, red,
|
||
green.
|
||
|
||
Create a consumer with the filter `color='red'`.
|
||
|
||
```java
|
||
MessageConsumer redConsumer = redSession.createConsumer(queue, "color='red'");
|
||
```
|
||
|
||
The `redConsumer` has a filter that only matches "red" messages. The
|
||
`redConsumer` will receive 3 messages.
|
||
|
||
```
|
||
red, red, red
|
||
```
|
||
|
||
The resulting queue would now be
|
||
|
||
```
|
||
green, green, green
|
||
```
|
||
|
||
## Alternate Ways to Determine Routing Type
|
||
|
||
Typically the routing type is determined either by the static XML configuration
|
||
or by the `default-address-routing-type` and `default-queue-routing-type`
|
||
`address-setting` elements used for [automatic address and queue
|
||
creation](#automatic-address-queue-management). However, there are two other
|
||
ways to specify routing type:
|
||
|
||
- a configurable prefix which client applications can use when sending
|
||
messages or creating consumers
|
||
- a property client applications can set on the messages they send
|
||
|
||
### Using a Prefix to Determine Routing Type
|
||
|
||
These prefixes are configured using the `anycastPrefix` and `multicastPrefix`
|
||
parameters within the URL of the `acceptor` which the client is using. When
|
||
multiple values are needed, these can be separated by a comma.
|
||
|
||
#### Configuring an Anycast Prefix
|
||
|
||
In `etc/broker.xml`, add the `anycastPrefix` to the URL of the desired
|
||
`acceptor`. In the example below, the acceptor is configured to use `queue/`
|
||
for the `anycastPrefix`. Client code can specify `queue/foo/` if the client
|
||
wants anycast routing.
|
||
|
||
```xml
|
||
<acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP;anycastPrefix=queue/</acceptor>
|
||
```
|
||
|
||
Consider, for example, a STOMP client that wants to send a message using
|
||
anycast semantics to a queue that doesn't exist. Consider also that the broker
|
||
is configured to auto-create addresses and queues, but the
|
||
`default-address-routing-type` and `default-queue-routing-type` are both
|
||
`MULTICAST`. Since the `anycastPrefix` is `queue/` it can just send a message
|
||
to `queue/foo` and the broker will automatically create an address named `foo`
|
||
with an anycast queue also named `foo`.
|
||
|
||
#### Configuring a Multicast Prefix
|
||
|
||
In `etc/broker.xml`, add the `multicastPrefix` to the URL of the desired
|
||
`acceptor`. In the example below, the acceptor is configured to use `topic/`
|
||
for the `multicastPrefix`. Client code can specify `topic/foo/` if the client
|
||
wants multicast routing.
|
||
|
||
```xml
|
||
<acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP;multicastPrefix=topic/</acceptor>
|
||
```
|
||
|
||
Consider, for example, a STOMP client that wants to create a subscription with
|
||
multicast semantics on an address that doesn't exist. Consider also that the
|
||
broker is configured to auto-create addresses and queues, but the
|
||
`default-address-routing-type` and `default-queue-routing-type` are both
|
||
`ANYCAST`. Since the `multicastPrefix` is `topic/` it can just subscribe to
|
||
`topic/foo` and the broker will automatically create an address named `foo`
|
||
with a multicast queue for the subscription. Any messages sent to `foo` will
|
||
then be routed to the subscription queue.
|
||
|
||
### Using a Message Property to Determine Routing Type
|
||
|
||
The `_AMQ_ROUTING_TYPE` property represents a `byte` value which will be used
|
||
by the broker to determine the routing type when a message is _sent_. Use `0`
|
||
for anycast routing or `1` for multicast routing.
|
||
|
||
> **Note:**
|
||
>
|
||
> A message will **only** be routed to queues which match its
|
||
> `_AMQ_ROUTING_TYPE` property value (if any). For example, if a message with
|
||
> an `_AMQ_ROUTING_TYPE` value of `1` (i.e. multicast) is sent to an address
|
||
> that only has anycast queues then the message won't actually be routed to any
|
||
> of the queues since the routing types don't match. If no `_AMQ_ROUTING_TYPE`
|
||
> is set then the message will be routed to all the queues on the address
|
||
> according to the queues' routing semantics.
|
||
|
||
## Configuring Addresses and Queues via Address Settings
|
||
|
||
This content has been relocated to its [own chapter](address-settings.md). |