Skip to main contentSkip to user menuSkip to navigation

Apache ActiveMQ

Design Apache ActiveMQ systems with queue capacity, flow control, persistence, redelivery, dead letters, failover, and idempotent consumers.

45 min readIntermediate
Not Started
Loading...

What is Apache ActiveMQ?

Apache ActiveMQ is a family of message brokers that lets applications communicate asynchronously. A producer sends a message to a broker-managed destination, and a consumer processes it later. The broker absorbs timing differences so the producer does not need to wait for the consumer to be online or finish its work.

The project has two broker implementations. ActiveMQ Classic is the established JMS broker used by the configuration and delivery examples in this lesson. ActiveMQ Artemis is the newer broker with a different core architecture and configuration model. Do not treat their tuning knobs or deployment files as interchangeable.

The core invariant is: the broker owns message availability; the application owns the business outcome. Acknowledgement, persistence, redelivery, and failover reduce specific loss windows, but consumers still need idempotency for ambiguous outcomes.

Follow a message from send to business commit

JMS separates the API contract from the broker implementation. Application code creates a connection, session, destination, producer, and consumer. ActiveMQ Classic then routes and stores messages according to destination and broker policy.

ActiveMQ Classic delivery path

Persistence and settlement protect different boundaries: the broker stores a message, while the consumer commits the business effect.

Create

Producer

Builds a message with a destination, stable business event ID, persistence mode, priority, and optional expiration.

Route

Broker destination

Accepts the send, applies queue or topic policy, and controls dispatch when consumers or broker resources fall behind.

Persist

Message store

Journals persistent messages. ActiveMQ Classic commonly uses KahaDB as its local persistence adapter.

Process

Consumer

Runs the handler and acknowledges or commits the delivery according to the JMS session mode.

Commit

Business store

Applies the domain mutation and records the event ID atomically when possible.

Three signals answer different questions:

  • A successful send says the broker accepted the message according to the selected producer and persistence semantics.
  • A consumer acknowledgement or session commit says the delivery can advance at the broker.
  • A business receipt says the application has already applied this event and can make a replay harmless.

Choose the destination from the delivery contract

Queues and topics are not styling choices. They determine who receives a copy and what happens while a consumer is disconnected.

One consumer per message

Queue

Use competing consumers to distribute independent work. Each message is dispatched to one available consumer, subject to acknowledgement, redelivery, ordering, and prefetch behavior.

Online subscribers

Non-durable topic

Use when every currently connected subscriber should receive its own copy and missing messages during disconnection is acceptable.

Offline continuity

Durable subscription

Use when one logical topic subscriber must retain matching messages while disconnected. Stable subscription identity, cleanup, storage, and lag monitoring become operational responsibilities.

Before creating a destination, decide:

  • whether work is shared or copied to independent subscribers;
  • whether offline consumers must catch up;
  • which ordering key, selector, expiration, and priority rules are actually required;
  • how much retained backlog the broker may hold before producers slow down;
  • who owns stale durable subscriptions and destination cleanup.

Turn workload assumptions into a recovery envelope

There is no portable messages-per-second limit for ActiveMQ. Payload size, persistence, disk latency, acknowledgement mode, selectors, prefetch, network, consumer code, and broker version all change the result. Start with arithmetic you can explain, then load test the exact deployment.

Choose a workload and adjust arrival rate, consumers, persistent share, and consumer interruption. The planner reserves 25% of measured handler capacity for variance and catch-up; it does not claim a broker benchmark.

Backlog and recovery lab

Can the consumers recover after an interruption?

Loading the ActiveMQ workload model.

Loading the capacity model...

Executable backlog and catch-up estimate

The raw persistent-payload result excludes KahaDB journal and index overhead, filesystem behavior, backups, replicas, temporary storage, and retention cleanup. Measure those factors before setting store limits.

Inject delivery ambiguity and broker pressure

ActiveMQ Classic can redeliver after a transacted session rolls back or closes before commit, after Session.recover() in CLIENT_ACKNOWLEDGE, or when a client connection times out. Once the configured maximum redeliveries is exceeded, the client can send a poison acknowledgement so the broker routes the message to a dead-letter queue.

Select each scenario and trace the active path. Compare a retryable unknown outcome with a permanent poison message and a capacity failure.

A dead-letter queue is quarantine, not success. Alert on arrivals, preserve message identity, record the failure reason, repair the cause, and replay at a rate the healthy path can absorb.

Make repeated delivery produce one result

The dangerous failure is a successful business commit followed by a lost or late acknowledgement. The broker cannot inspect an external payment or order database, so it must treat the delivery as uncertain and may send the message again.

Use a stable event ID and commit an inbox receipt with the domain mutation. The unique receipt turns a repeated delivery into a lookup of the first result.

Executable idempotent consumer model

The example uses SQLite so it runs without a broker or third-party package. In a real consumer, settle the JMS delivery only after the database transaction succeeds. A process-local set is not enough because it disappears on restart and cannot coordinate several consumer instances.

Bound broker resources instead of hiding overload

ActiveMQ Classic uses producer flow control when configured destination or system usage limits are reached. A synchronous producer may block until resources become available or fail according to policy. This is backpressure, not a hung broker.

Dispatch working set

Memory usage

Protects heap used for messages and dispatch. Store-based cursors can page pending work rather than keeping every message body in memory.

Persistent backlog

Store usage

Bounds persistent message storage such as KahaDB. A rising oldest-message age usually reveals consumer trouble before the disk limit is reached.

Non-persistent spill

Temporary usage

Bounds temporary storage used when non-persistent messages cannot remain in memory. Transient delivery still needs a pressure policy.

Illustrative ActiveMQ Classic resource and DLQ policy

The configuration binds OpenWire to localhost for a safe local example. A production deployment also needs explicit authentication, authorization, encrypted transport, secret management, network policy, backup, and a tested high-availability design.

Operate the end-to-end message outcome

Queue depth alone is incomplete: ten old messages can be more urgent than ten thousand fresh ones. Monitor time, resource pressure, and the final business effect together.

  1. 1

    Design

    Declare the contract

    Record destination type, owner, schema, event ID, persistence, expiration, ordering, selector, acknowledgement, redelivery, and DLQ policy.

  2. 2

    Capacity

    Measure the envelope

    Load test realistic payloads and broker storage while downstream dependencies exhibit normal latency and failure behavior.

  3. 3

    Consume

    Protect correctness

    Validate schema, make the handler idempotent, bound processing time, and settle only after the durable business result.

  4. 4

    Observe

    Watch age and pressure

    Alert on oldest-message age, enqueue and dequeue rates, inflight work, redelivery, DLQ growth, memory usage, store usage, and final business latency.

  5. 5

    Operate

    Rehearse recovery

    Test consumer loss, broker reconnect, store pressure, poison messages, bounded replay, and reconciliation after an ambiguous commit.

Before launch, verify:

  • the failover URI has bounded reconnect and send behavior appropriate to callers;
  • durable subscriptions and inactive destinations have explicit ownership and cleanup;
  • message size, prefetch, concurrency, and selectors are tested with production skew;
  • backups and broker failover are restored in a drill, not only described in a runbook;
  • dashboards distinguish broker acceptance from the final business outcome.

Know which ActiveMQ broker you are operating

ActiveMQ Classic is a practical fit for mature JMS applications, integration-heavy systems, and protocol bridging where its operational model is already understood. Evaluate Artemis separately when building a new deployment; it uses addresses, queues, and anycast or multicast routing under a different broker architecture.

Choose a database, object store, workflow engine, or analytical log when the dominant need is mutable state, large payload storage, long-running orchestration, or broad replay and stream processing rather than message dispatch.

Primary references:

No quiz questions available
Could not load questions file
Spotted an issue or have a better explanation? This page is open source.Edit on GitHub·Suggest an improvement