6 minute read

The Advanced Message Queuing Protocol (AMQP) is an open standard application layer protocol for message-oriented middleware. The defining features of AMQP are message orientation, queuing, routing (including point-to-point and publish-and-subscribe), reliability and security.

AMQP mandates the behavior of the messaging provider and client to the extent that implementations from different vendors are interoperable, in the same way as SMTP, HTTP, FTP, etc. have created interoperable systems.

Previous standardizations of middleware have happened at the API level (e.g. JMS) and were focused on standardizing programmer interaction with different middleware implementations, rather than on providing interoperability between multiple implementations.

Unlike JMS, which defines an API and a set of behaviors that a messaging implementation must provide, AMQP is a wire-level protocol. A wire-level protocol is a description of the format of the data that is sent across the network as a stream of bytes.

Consequently, any tool that can create and interpret messages that conform to this data format can interoperate with any other compliant tool irrespective of implementation language.

The AMQP model

AMQP defines a series of entities.

From the perspective of interconnection, the most relevant are:

  • The message broker: a server to which AMQP clients connect using the AMQP protocol. Message brokers can run in a distributed environment, but this capability is implementation specific and not covered by the specification.
  • User: a user is an entity that, by presenting credentials such as a password, may be authorized (or may not be) to connect to a broker.
  • Connection: a physical connection using for example TCP / IP or SCTP. A connection is tied to a user.
  • Channel - A logical connection that is attached to a connection. Thus, communication through a channel has a state. Those clients that carry out concurrent operations through the same connection must maintain a different channel for each of them. Clients using a thread-based model for concurrency can, for example, encapsulate the channel declaration in a local variable for each thread.

The entities used to send and receive messages in particular are all declared within a channel. A declaration guarantees the client who makes it that the entity exists (or was previously declared by another client).

Any attempt to declare a named entity with different properties than it had when it was declared results in an error. In order to change the properties of a named entity, it must first be deleted prior to its new creation.

Some of these entities are named. Its name must be unique within the scope of the entity and its broker. Since clients typically do not have the means to obtain a list of all available named entities (at least there is no such operation defined within the AMQP specification), it is knowledge of the name of an entity that enables the client to perform operations.

Names use UTF-8 encoding, must be 1 to 255 characters long, and must begin with a digit, letter, or underscore.

Exchanges

The exchanges are the entities to which the messages are sent.

They have a name as well as a type and some properties such as:

  • passive: the exchanger will not be declared but an error will occur if it does not exist.
  • durable: the exchanger will survive an exchanger reset.
  • auto-delete: the exchanger will be deleted as soon as there are no longer any queues attached to it. Those exchangers that have never had linked queues will never be auto-deleted.

Queues

Queues are the entities that receive messages. They have a name and properties but they have no type. Clients can subscribe to queues, with the effect that the message broker will deliver (via a push mechanism, that is, actively by the broker) the contents of the queue to the clients to the clients. Alternatively clients can actively jump messages from the queue as they see fit (pull mechanism).

The queue ensures that messages are delivered in the same order that they arrived on the queue; this ordering is commonly known as FIFO. In some cases of rerouting (eg due to a failure involving a corridor restart) this order is not guaranteed.

Queue properties include:

  • Alternative exchanger: when a message is rejected by a subscriber or is orphaned due to the destruction of a queue, they are rerouted to an alternative exchanger and deleted from this queue.
  • passive: the queue will not be declared but an error will occur if it does not exist.
  • Enduring - The queue will survive a corridor reset.
  • exclusive - There can only be one client for this specific queue.
  • auto-delete: the queue will be deleted as soon as there are no active subscriptions for it. This property shares the same limitation as the auto-delete property for exchangers: if no subscription has ever been active for this queue, it will not be auto-deleted. An exclusive queue, however, will always be self-clearing when the client logs out.
  • Messages

    The messages have no name and are published on an exchanger. They consist of a header and a content body. While the body contains opaque data, the header contains a number of optional properties:
    • routing-key: This field is used in different ways depending on the type of exchanger.
    • Immediate: the message will be treated as impossible to route if at least one of the queues that should receive the message has no subscription.
    • delivery mode: indicates that a message may require durability. Only for this type of message can the broker make an attempt (best-effort) to prevent the loss of the message before it is consumed. If there is any uncertainty on the broker's side about the correct reception of the message (for example in case of errors), he can optionally deliver the same message more than once. Non-persistent modes of delivery do not exhibit this type of behavior.
    • priority: an indicator (in the range 0 to 9) that one message takes precedence over others. expiration: the duration in milliseconds before the broker can treat the message as impossible to route.

    Binding

    A binding is a relationship between a queue and an exchanger that specifies how messages flow from the exchanger to the queue. The binding properties are consistent with the routing algorithm used by the exchangers. The bindings (and the algorithms of the interchangers) can be ordered on a scale from less to greater complexity:
    • Unconditional - The binding has no properties and claims all messages from the exchanger.
    • Conditional with a fixed string: The binding has one property, the routing key, and it claims all messages that have an identical routing key.
    • Conditional with a pattern recognition: The binding has one property, the routing key, and claims all messages that are detected by a pattern recognition algorithm. Any arbitrary pattern syntax can be used. AMQP implements topic recognition.
    • Conditional with multiple fixed strings: the binding has a table of properties, the arguments, and claims all the messages whose headings correspond to these arguments, using logical AND or OR operations to combine the different matches.
    • Conditional with an algorithmic comparison: The binding takes an algorithmic expression (such as a WHERE clause in a SELECT statement in SQL) and claims all messages whose headings match this expression.
    • Conditional with content inspection: binding specifies arbitrary criteria that can only be resolved by inspecting the specific content of the message.