Architecture¶
Internals of RabbitMQ 4.x: the Erlang/OTP runtime model, the Khepri metadata store, the three queue types (quorum, classic, stream), exchanges, and the federation/shovel plugins.
Component Overview¶
flowchart TB
Client["Client (AMQP, MQTT, STOMP, Stream protocol)"]
subgraph Node["RabbitMQ Node — Erlang VM (BEAM)"]
ConnSup["Connection supervisor"]
ChannelSup["Channel supervisor"]
ProtoHandler["Protocol Handler\n(amqp091, amqp10, mqtt, stomp, stream)"]
ExchangeRouter["ExchangeRouter"]
DirectExchange["DirectExchange"]
TopicExchange["TopicExchange"]
FanoutExchange["FanoutExchange"]
HeadersExchange["HeadersExchange"]
ConsHashEx["Consistent-Hash Exchange (plugin)"]
QQ["QuorumQueue\n(Raft + log_segments)"]
ClassicQ["ClassicQueue\n(in-memory + WAL)"]
Stream["Stream\n(append segments)"]
Khepri["Khepri\n(Raft metadata)"]
Mgmt["rabbitmq_management"]
Prom["rabbitmq_prometheus"]
end
Client --> ProtoHandler
ProtoHandler --> ChannelSup
ChannelSup --> ExchangeRouter
ExchangeRouter --> DirectExchange
ExchangeRouter --> TopicExchange
ExchangeRouter --> FanoutExchange
ExchangeRouter --> HeadersExchange
DirectExchange --> QQ
TopicExchange --> Stream
FanoutExchange --> ClassicQ
HeadersExchange --> QQ
ConsHashEx --> QQ
Khepri -.holds.-> ExchangeRouter
Khepri -.holds.-> QQ
Khepri -.holds.-> Stream
Components¶
| Component | Role |
|---|---|
| Erlang VM (BEAM) | Concurrency model with millions of lightweight processes; per-connection / per-channel / per-queue processes. |
| Connection | One Erlang process per AMQP TCP connection. Holds heartbeats and channel multiplex state. |
| Channel | Sub-stream within a connection; cheaper than a TCP connection. Holds prefetch, ack state, transaction state. |
| Exchange | Routing element with no own message storage. Implementation type chosen at declaration. |
| Binding | Edge from Exchange→Queue (or Exchange→Exchange) with optional routing-key + arguments. |
| Queue (Quorum) | Raft-replicated, durable, work-queue oriented. |
| Queue (Classic) | Single-master, persisted via WAL+segment files; deprecated for replication. |
| Stream | Append-only segment log, Raft-replicated. Optimized for fan-out and high throughput. |
| Khepri | Metadata store: vhosts, users, exchanges, bindings, policies. Raft consensus, replaces Mnesia. |
| Plugins | Federation, Shovel, MQTT, STOMP, Stream, Web-MQTT, Web-STOMP, Delayed Message, Consistent-Hash, OAuth 2.0, LDAP, Top, Tracing. |
AMQP 0-9-1 Routing Model¶
sequenceDiagram
participant P as Producer
participant C as Channel
participant E as Exchange
participant Q as Queue
participant Cn as Consumer
P->>C: basic.publish exchange=X routing_key=k
C->>E: route(k)
E->>Q: route by binding (k or pattern)
Q->>Q: append message
Q->>Cn: deliver (push) / Cn polls (pull)
Cn->>Q: basic.ack delivery-tag=N
Exchange types¶
| Type | Routing |
|---|---|
| direct | Exact routing key match → bound queue. |
| topic | Pattern routing key with * (one word) and # (zero+ words). |
| fanout | Broadcast to every bound queue. |
| headers | Match on message headers (x-match: all|any). |
| consistent-hash (plugin) | Hash routing key into one of N bound queues — partition-style sharding. |
| random (plugin) | Pick a single bound queue at random. |
| delayed-message (plugin) | Hold messages with x-delay then re-route. |
Queue Types Deep Dive¶
Quorum Queue¶
sequenceDiagram
participant P as Producer
participant L as Leader
participant F1 as Follower 1
participant F2 as Follower 2
participant C as Consumer
P->>L: publish (channel)
L->>L: append to Raft log + WAL
L->>F1: AppendEntries
L->>F2: AppendEntries
F1->>L: ack
F2->>L: ack
Note right of L: quorum reached
L->>P: basic.ack confirm
L->>C: deliver
C->>L: basic.ack
L->>F1: replicate ack state
L->>F2: replicate ack state
- Built on the Ra Raft library by RabbitMQ team.
- Snapshots and log compaction prevent unbounded growth.
- Per-queue tunables:
x-delivery-limit,x-max-length,x-max-length-bytes,x-overflow,x-quorum-initial-group-size. - 4.x adds continuous queue membership reconciliation so adding/removing nodes rebalances queues automatically.
Classic Queue¶
- Single master process; mirrors are removed in 4.x.
- Used for ephemeral, exclusive, or auto-delete cases (RPC reply queues).
- Persistence via WAL + segment files; supports lazy mode (everything to disk immediately).
Stream¶
- Append-only segment files; consumers read by offset.
- Raft replication for durability.
- Pure stream protocol on TCP 5552; AMQP 0-9-1 access also possible (
x-queue-type: stream). - Use cases: high fan-out (every consumer reads every message), large historical replay.
Khepri (Metadata Store)¶
Khepri replaces Mnesia for vhost/user/exchange/binding/policy metadata.
| Trait | Mnesia (legacy) | Khepri (4.x) |
|---|---|---|
| Consensus | Custom (master–master quorum, partition strategy) | Raft |
| Network partition | Required pause_minority / autoheal |
Built-in: minority becomes read-only |
| Schema migrations | Manual + brittle | Versioned, auto-applied |
| Tooling | rabbitmqctl over Mnesia |
rabbitmqctl over Khepri (transparent) |
In 4.0 Khepri was opt-in. In 4.2+ Khepri is the default; Mnesia removal scheduled for a future major release.
Federation Plugin¶
Federation forwards messages between two RabbitMQ deployments by subscribing to upstreams and republishing to local exchanges/queues. Latency-tolerant; suitable for cross-region.
flowchart LR
UpstreamRabbit["Upstream RabbitMQ\n(US)"]
DownstreamRabbit["Downstream RabbitMQ\n(EU)"]
UpstreamEx["UpstreamExchange"]
DownstreamEx["DownstreamExchange"]
UpstreamRabbit --> UpstreamEx
UpstreamEx -. federation link .-> DownstreamEx
DownstreamEx --> DownstreamRabbit
Shovel Plugin¶
Shovel is a one-off message mover: fetch from source, publish to destination. Useful for migration windows or burning off backlog into a different broker.
Connection / Channel Lifecycle¶
stateDiagram-v2
[*] --> TCP: open
TCP --> Authenticated: SASL
Authenticated --> ChannelOpen: channel.open
ChannelOpen --> Idle
Idle --> Publishing: basic.publish
Idle --> Consuming: basic.consume
Publishing --> Idle: confirm/return
Consuming --> Idle: cancel
ChannelOpen --> ChannelClosed: channel.close
ChannelClosed --> [*]
Authenticated --> [*]: connection.close
Performance Characteristics¶
| Workload | Throughput |
|---|---|
| Quorum queue, persistent, R3 | ~30k–100k msg/sec/queue (NVMe) |
| Classic queue, persistent | ~50k–150k msg/sec/queue |
| Stream protocol (port 5552), R3 | 1M+ msg/sec/cluster |
| MQTT plugin, native | ~50k connected clients/node, ~50k pub/sec |
| Federation cross-WAN | Latency = WAN RTT + repeat overhead |
Benchmark caveat
These are order-of-magnitude figures from official RabbitMQ blogs and community benchmarks. Always run perf-test on representative hardware.
Comparison hooks¶
- vs Kafka — RabbitMQ wins on routing flexibility and AMQP 0-9-1 compatibility; Kafka wins on log replay throughput and analytic ecosystem.
- vs NATS — NATS wins on latency and footprint; RabbitMQ wins on routing primitives, dead-letter, and protocol breadth.
- vs Pulsar — Pulsar offers tiered storage and multi-tenancy out of the box; RabbitMQ uses vhosts + plugins for similar boundaries.