Skip to content

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.