Exchanges
What is an Exchange?
In AMQP 0-9-1, exchanges are the entities where publishers publish messages that are then routed to a set of queues or streams.
Exchanges, like other topology elements in AMQP 0-9-1, are declared by applications using client libraries.
The purpose of exchanges is to route all messages that flow through them to one or more queues, streams, or other exchanges.
The type of the exchange and the binding properties are used to implement the routing logic.
Exchanges Belong to Virtual Hosts
Like all other topology elements, every exchange belongs to one virtual host. This is true even for the system exchanges, which exist only in the default virtual host.
When a virtual host is created, a number of pre-declared exchanges will be automatically created in it.
Exchange Names
Every exchange must have a name.
One special exchange called the default exchange (see below) uses an empty string for its name when its specified as the publishing target.
In other contexts, say, permission management, the same exchange
can be referred to as "amq.default"
but this name cannot be used when publishing messages.
Exchange Types
Exchanges can be of different types. An exchange type controls how it routes the messages published to it. For example, one exchange type may use a topic (pattern)-based routing, while another can route all messages to every bound queue unconditionally.
RabbitMQ ships with multiple exchange types:
- Fanout: covered in tutorial 3
- Topic: covered in tutorial 5
- Direct: covered in tutorial 4
- Default direct exchange: a built-in direct exchange with special characteristics
- Local Random
- JMS Topic
- Consistent Hashing exchange
- Random exchange
- Recent history exchange
- Headers
Exchange types can be provided by plugins.
Fanout
Fanout exchanges route a copy of every message published to them to every queue, stream or exchange bound to it. The message's routing key is competely ignored.
See tutorial 3 to see how this exchange type is used.
Topic
Topic exchanges use pattern matching of the message's routing key to the routing (binding) key pattern used at binding time.
For the purpose of routing, the keys are separated into segments by .
. Some segments are populated by specific values,
while others are populated by wildcards: *
for exactly one segment and #
for zero or more (including multiple) srgments
For example,
- A binding (routing key) pattern of
"regions.na.cities.*"
will match message routing keys"regions.na.cities.toronto"
and"regions.na.cities.newyork"
but will not match"regions.na.cities"
because*
is a wildcard that matches exactly one segment - A binding (routing key) pattern
"audit.events.#"
will match"audit.events.users.signup"
and"audit.events.orders.placed"
but not"audit.users"
because the second segment does not match - A binding (routing key) pattern of
"#"
will match any routing key and makes the topic exchange act like a fanout for the bindings that use such a pattern
See tutorial 5 to see how this exchange type is used.
Direct
Direct exchanges route to one or more bound queues, streams or exchanges using an exact equivalence of a binding's routing key.
For example, a binding (routing) key of "abc"
will match "abc"
and "abc"
only.
See tutorial 4 to see how this exchange type is used.
Default Exchange
The default exchange is a direct exchange that has several special properties:
- It always exists (is pre-declared)
- Its name for AMQP 0-9-1 clients is an empty string (
""
) - When a queue is declared, RabbitMQ will automatically bind that queue to the default exchange using its (queue) name as the routing key
This provides AMQP 0-9-1 applications with a mechanism that makes it convenient to publish "directly" to a queue using only its name, even though there's still a direct exchange involved under the hood.
The default exchange is used for its special properties. It is not supposed to be used as "regular" exchange that applications explicitly create bindings for.
For such cases where a direct exchange and a custom topology are necessary, consider declaring and using a separate direct exchange.
Local Random Exchange
Local Random is a specialized exchange type covered in a separate documentation guide.
JMS Topic Exchange
JMS Topic exchange was introduced to implement certain JMS features for the RabbitMQ JMS client.
What are Bindings?
Exchanges, when declared, are not aware of any queues or streams. An initially declared exchange is an empty named routing table.
In order to fill the table with some routing rules, a queue, stream or another exchange (see below) must be bound to the exchange. In other words, an application must create a binding between the exchange and a queue or a stream.
A binding has the following properties:
- Source name: a name of the exchange this binding is added to
- Destination name: a name of the target queue, stream, or another exchange
- Destination type (
queue
for queues and streams,exchange
for exchange-to-exchange bindings) - An optional map of arguments, which certain exchange types can use (e.g. the headers exchange)
Binding Durability
Bindings inherit durability from their source and destination. As such, bindings can be
- Fully durable: both their exchange and destination/queue/stream are durable
- Semi-durable: in practice this means that their their exchange is durable and their destination/queue/stream is transient
- Fully transient: both their exchange and destination/queue/stream are transient
Support for semi-durable and fully transient bindings will be dropped in the future.
Binding durability can matter when bindings are used with transient classic queues.
When a node, hosting non-replicated (classic) queues, is stopped, all of the transient queues and semi-durable bindings on it will be removed.
In the case of large topologies, this can take time and when the node comes back online and applications reconnect, semi-durable and transient bindings can be removed and re-added concurrently, which can result in an inconsistent bindings state and confusing routing behavior.
To avoid the aforementioned problem, only using durable (replicated or not) queues, optionally with a reasonably short TTL, and streams, and limit the use of transient queues, for example, to publishing using the default exchange.
Pre-Declared Exchanges
Per AMQP 0-9-1 Spec
Per AMQP 0-9-1 spec, every virtual host contains a number of pre-declared exchanges:
- The default exchange
- A number of
amq.*
exchanges, one per type, e.g.amq.fanout
oramq.topic
System Exchanges
amq.rabbitmq.log
is a system topic exchange used by an opt-in logging featureamq.rabbitmq.event
is a system topic exchanged used by the internal events mechanism
Exchange Properties
Exchanges have several key properties that can be specified at declaration times
Durability
Just like queues, exchanges can be durable or transient. However, transient exchanges are very rarely used in practice.
As a rule of thumb, consider using durable exchanges for the following reasons:
- Applications with transient or client-specific state rarely need (or use) custom exchanges and instead rely on the pre-declared ones (such as
amq.topic
) - Further in the 4.x series, support for transient (non-durable) entities will be removed when Khepri becomes the only supported metadata store
Auto-Deletion
Auto-deleted queues are deleted when their last binding is removed.
This requires that at least such a binding exists (created); exchanges that are never bound won't be deleted by this mechanism.
Optional Arguments
Optional exchange arguments, also known as "x-arguments" because of their field name in the AMQP 0-9-1 protocol, is a map (dictionary) of arbitrary key/value pairs that can be provided by clients when a queue is declared.
The map is used by certain features and exchange types, such as alternate exchanges and the headers exchanges.
These optional arguments usually can be dynamically changed after queue declaration via policies.
For keys that can be set via policies, always first consider using a policy instead of setting these values in application code
Optional exchange arguments can be set differently:
- To groups of queues using policies (recommended)
- On a per-exchange basis when a queue is declared by a client
The former option is more flexible, non-intrusive, does not require application modifications and redeployments. Therefore it is highly recommended for most users. Note that some optional arguments such as queue type or max number of priorities can only be provided by clients because they cannot be dynamically changed and must be known at declaration time.
The way optional arguments are provided by clients varies from client library
to client library but is usually an argument next to the durable
,
auto_delete
and other arguments of the function (method) that
declares queues.
Optional Arguments and Policy-Defined Key Precedence
When the same key is provided by both client-provided x-arguments
and by a policy,
the former take precedence.
However, if an operator policy is also used, that will take precedence over the client-provided arguments, too. Operator policies are a protection mechanism and override client-provided values and user policy values.
For numerical values, the lower value of the two will be used. If an application needs or chooses to use a lower value, that will be allowed by an operator policy. A value higher than that defined in the operator policy, however, cannot be used.
Use operator policies to introduce guardrails for application-controlled parameters related to resource use (e.g. peak disk space usage).
Exchange-to-Exchange Bindings
Besides queues and streams, an exchange can be bound to another exchange using an AMQP 0-9-1 protocol extension in RabbitMQ called exchange-to-exchange bindings, or E2E for short.
Applications then publish to the source exchange, which routes messages to the destination exchange.
For efficiency reasons, a message published to a source exchange that has E2E bindings will be routed only once using the total set of available bindings on both on the source and all the destination exchanges bound to it.
In other words, E2E bindings do not republish messages, they are a routing extension that respect the types of both the source and the destination exchange.
This means that the destination exchange's ingress (inbound) message rate metric won't be updated. Metrics for the target queues and streams will be, whether they are bound to the source exchange or the destination one.
Alternate Exchanges
Alternate Exchanges is a feature that allows an exchange that was unable to route a message because there were no suitable bindings to delegate routing to a different exchange.
Alternate exchanges are useful when performing topology migrations or collecting unroutable messages.
System Exchanges
RabbitMQ provides a number of built-in exchanges for logging and audit purposes:
amq.rabbitmq.log
is a system topic exchange used by an opt-in logging featureamq.rabbitmq.event
is a system topic exchanged provided by a built-in plugin and used by the internal events mechanismamq.rabbitmq.trace
is used by the message tracing mechanism
Both exchanges make it possible to develop custom log collection and auditing applications that only need an AMQP 0-9-1 client library.