AMQP
ActiveAMQP (Advanced Message Queuing Protocol) is an open standard for message-oriented middleware. Publishers send messages to exchanges; exchanges route messages to queues based on routing rules; consumers receive messages from queues. AMQP decouples producers and consumers. RabbitMQ implements AMQP 0-9-1. AMQP 1.0 is the ISO/IEC standard (2014) with a different wire format adopted by Azure Service Bus, Apache Qpid, and ActiveMQ Artemis.
In one line
AMQP (OASIS 1.0, 2012 – ISO/IEC 19464:2014) is a binary messaging protocol for message queues and pub/sub. The AMQP 0-9-1 model (used by RabbitMQ): publishers send to exchanges, exchanges route to queues via bindings, consumers subscribe to queues. Four exchange types: direct (exact routing key), fanout (broadcast), topic (wildcard routing key), headers (attribute matching). AMQP 1.0 (Azure Service Bus, Apache Qpid) is a different wire format with the same messaging semantics.
Quick Reference
| Field | Size | Description |
|---|---|---|
| Port | 5672 (plain), 5671 (TLS) | IANA-assigned ports. 5672 for plaintext AMQP. 5671 for AMQP over TLS (AMQPS). RabbitMQ management UI uses 15672. |
| Exchange | 4 types | The routing component. Publishers send to exchanges, not directly to queues. Exchange types: direct, fanout, topic, headers. Default exchange routes by queue name. |
| Queue | Message buffer | Stores messages until consumers receive them. Properties: durable (survives broker restart), exclusive (single connection), auto-delete (deleted when last consumer disconnects), arguments (TTL, max length, dead-letter exchange). |
| Binding | Exchange-to-queue link | A rule connecting an exchange to a queue. Bindings have routing keys (for direct/topic) or header arguments (for headers exchange). A queue can be bound to multiple exchanges. |
| Routing key | string | Published with each message. Exchanges use routing keys to determine which queues to deliver to. Format depends on exchange type: exact string (direct), dot-separated pattern (topic), ignored (fanout). |
| Acknowledgements | ack/nack | Consumer sends ack after processing. If consumer crashes before ack, broker requeues message. Basic.ack, Basic.nack (with requeue flag), Basic.reject. Unacked messages in-flight limit via prefetch count (QoS). |
| Publisher confirms | async ack | Broker confirms each message was received and persisted (if durable). Enables reliable publishing without transactions. Stripe-style reliable send pattern. |
| Dead Letter Exchange | DLX | Messages rejected, nacked without requeue, or expired (TTL) are routed to a DLX. Used for retry queues and poison message handling. |
Key Characteristics
Exchange-based routing
Publishers don't know which queues exist. They publish to an exchange with a routing key. The exchange routes based on bindings. This decouples publishers from consumers completely.
Delivery guarantees
Consumer acknowledgements + publisher confirms + durable queues = at-least-once delivery. Combined with idempotent consumers, you get effectively-once processing.
AMQP 0-9-1 vs 1.0
RabbitMQ uses AMQP 0-9-1, which is NOT compatible with AMQP 1.0 (Azure Service Bus, ActiveMQ Artemis). The exchange/queue model exists only in 0-9-1. Choose client libraries accordingly.
Prefetch and flow control
Basic.qos sets prefetch count – the number of unacknowledged messages a consumer can hold at once. Prevents fast publishers from overwhelming slow consumers.
Message Format
// RabbitMQ AMQP 0-9-1 – Node.js amqplib example
const amqp = require('amqplib');
const conn = await amqp.connect('amqp://user:pass@rabbitmq:5672');
const ch = await conn.createChannel();
// Declare durable exchange and queue
await ch.assertExchange('orders', 'topic', { durable: true });
await ch.assertQueue('orders.eu', {
durable: true,
arguments: {
'x-dead-letter-exchange': 'orders.dlx',
'x-message-ttl': 300000 // 5 min TTL
}
});
await ch.bindQueue('orders.eu', 'orders', 'order.created.eu.*');
// Publish with publisher confirms
await ch.assertConfirm();
ch.publish('orders', 'order.created.eu.de',
Buffer.from(JSON.stringify({ orderId: 'ord_123', country: 'de' })),
{ persistent: true, contentType: 'application/json' }
);// Consumer with manual acknowledgement
const ch = await conn.createChannel();
await ch.prefetch(10); // max 10 unacked messages
ch.consume('orders.eu', async (msg) => {
if (!msg) return;
try {
const order = JSON.parse(msg.content.toString());
await processOrder(order);
ch.ack(msg); // success – remove from queue
} catch (err) {
if (isRetryable(err)) {
ch.nack(msg, false, true); // requeue once
} else {
ch.nack(msg, false, false); // reject to DLX
}
}
}, { noAck: false });
// AMQP message properties
// deliveryMode: 1=transient, 2=persistent (survives restart)
// expiration: TTL in milliseconds (string)
// messageId, correlationId, replyTo: for RPC pattern
// headers: map<string, any> for headers exchange routing