Chapters

10 AMQP Delivery: Sizing and Reliability Contracts

amqp
arch
messages
delivery
reliability
dlq

Start with the story: An AMQP message is a parcel with a label, a body, and a delivery receipt path. The chapter is about choosing when that parcel may be dropped, retried, acknowledged, or parked for investigation.

10.1 Start With the Decision

Five hundred machines can turn a safe message rule into a queue bottleneck. Size, rate, prefetch, and failure flow must be counted.

10.2 Route Overview

This is part 2 of 2. Review AMQP Delivery: Guarantees and Acknowledgements for the preceding evidence.

10.3 Learning Objectives

  • Calculate smart-factory message volume and throughput.
  • Verify an AMQP reliability chain with explicit contracts.

10.4 Chapter Roadmap

  • Worked Example: Smart Factory Message Sizing
  • Putting Numbers to It
  • Checkpoint: Sizing the Reliability Chain
  • Knowledge Check
  • Quiz: Match Concepts to Definitions
  • Label the Diagram
  • Code Challenge
  • Order the Steps
  • Design Contract: Delivery Reliability Chain
  • AMQP Delivery Reliability Chain Contracts
  • Summary
  • What’s Next
  • Key Takeaway

10.5 Worked Example: Smart Factory Message Sizing

Now combine structure, guarantees, acknowledgments, and DLQ handling. Pay for reliability where the consequence justifies it.

Scenario: A pharmaceutical manufacturing plant monitors 500 machines via AMQP. Each machine publishes three types of messages with different delivery requirements:

Message TypeFrequencyPayloadDelivery Need
Temperature telemetryEvery 5 seconds120 bytes JSONOccasional loss OK
Quality alertOn threshold breach (~10/hour/machine)350 bytes JSONMust not be lost
Batch completion event~2 per hour per machine800 bytes JSONExactly once (audit trail)

Step 1: Calculate message rates and bandwidth

  • Telemetry: 500 machines x 1 msg/5s = 100 msg/s
  • Quality alerts: 500 x 10/hr = 5,000/hr = 1.39 msg/s
  • Batch events: 500 x 2/hr = 1,000/hr = 0.28 msg/s
  • Total: ~102 msg/s

Step 2: Calculate per-message AMQP overhead

Each AMQP message includes:

  • Frame header: 8 bytes
  • Method frame (basic.publish): ~40 bytes (exchange name, routing key)
  • Content header: ~60 bytes (properties: delivery_mode, content_type, timestamp, message_id, correlation_id)
  • Content body frame: 8 bytes header + payload

Total overhead per message: ~116 bytes

Step 3: Choose delivery mode for each type

TypeQoSOverhead per msgRationale
TelemetryAt-most-once120 + 116 = 236 BNext reading in 5s replaces any loss
Quality alertAt-least-once350 + 116 = 466 B + ACK (40 B)Must arrive; dedup via message_id
Batch eventExactly-once800 + 116 = 916 B + TX overhead (~200 B)Audit requires no duplicates

Step 4: Aggregate bandwidth

  • Telemetry: 100 msg/s x 236 B = 23,600 B/s = 189 Kbps
  • Alerts: 1.39 msg/s x 506 B = 703 B/s = 5.6 Kbps
  • Batch: 0.28 msg/s x 1,116 B = 312 B/s = 2.5 Kbps
  • Total: ~197 Kbps (well within a 1 Mbps LAN connection)

AMQP protocol overhead per message consists of multiple frame components:

OverheadAMQP=frameheader+methodframe+contentheader+bodyframe\text{Overhead}_{\text{AMQP}} = \text{frame}_{\text{header}} + \text{method}_{\text{frame}} + \text{content}_{\text{header}} + \text{body}_{\text{frame}} =8B+40B+60B+8B=116 bytes minimum= 8B + 40B + 60B + 8B = 116 \text{ bytes minimum}

Message efficiency for different payload sizes:

Efficiency=payloadpayload+overhead×100%\text{Efficiency} = \frac{\text{payload}}{\text{payload} + \text{overhead}} \times 100\%
PayloadTotal SizeEfficiency
10 B126 B7.9% (poor)
120 B236 B50.8% (moderate)
800 B916 B87.3% (good)

For telemetry with 120-byte payloads, nearly half the bandwidth is protocol overhead. Batching 10 readings into one 1,200-byte message improves efficiency from 51% to 91%, saving (10×236B)(1,200B+116B)=1,044B(10 \times 236B) - (1,200B + 116B) = 1,044B per 10 readings (44% reduction).

10.5.1 Interactive Calculator: AMQP Message Sizing

10.5.2 Interactive Calculator: AMQP Bandwidth Requirements

Step 5: Broker memory for persistent sessions

Quality alerts and batch events use persistent delivery (delivery_mode=2):

  • Persistent messages per second: 1.39 + 0.28 = 1.67 msg/s
  • Average persistent message size: ~810 bytes (weighted: (1.39 x 506 + 0.28 x 1116) / 1.67 ≈ 608 B on-wire; ~810 B with broker internal framing)
  • If a consumer goes offline for 10 minutes: 1.67 x 600 = 1,002 messages ≈ ~810 kB queued
  • With 5 consumers, worst case: ~4 MB broker memory for queued messages

Conclusion: The telemetry (98% of messages) uses fire-and-forget, keeping broker load minimal. Only the 2% of messages that matter (alerts + batch events) use persistent delivery, consuming modest broker resources. Using exactly-once for all messages would increase bandwidth to ~360 Kbps (vs. 197 Kbps) — roughly 1.8x — due to adding ~200 bytes of transaction overhead per telemetry message. That overhead is waste for data that is replaced every 5 seconds.

Broker BexCheckpoint: Sizing the Reliability Chain

You now know:

  • The factory example produces about 102 messages per second from 500 machines.
  • Telemetry is 98% of traffic, so at-most-once keeps the total near 197 Kbps.
  • Persistent alerts and batch events are only 2% of messages, but they drive offline broker memory.

10.6 Knowledge Check

Test your understanding of message structure and delivery guarantees.

10.7 Design Contract: Delivery Reliability Chain

Reliable AMQP delivery is a chain, not one setting. The deeper treatment now lives in AMQP Delivery Reliability Chain Contracts, covering publisher confirms, durable queues, persistent messages, manual acknowledgments, idempotent redelivery, and DLX retry/parking evidence paths.

10.8 AMQP Delivery Reliability Chain Contracts

Start with the story: Reliability in AMQP is not one magic checkbox. It is a chain of receipts: the producer needs a broker confirm, the broker needs durable storage, the message needs persistence, and the consumer must acknowledge only after the real work is done.

10.8.1 Learning Objectives

Prove Every Link in One Alarm Chain

Picture a site unit sending a valve alarm to an incident worker. The message reaches a queue, the worker writes the incident, and then the worker crashes before it says the job is done. The next worker may see the same alarm, so the team must prevent a second incident without losing the first.

Trace one alarm from local copy to accepted store, waiting queue, worker, final record, and done signal. Name what each signal proves and what it does not. Keep one alarm id through every link so a resend or redelivery can be joined to the same physical event.

Test a failed send, a store restart, a message held only in memory, a worker crash before and after the write, a rejected item, and a full retry path. Check both loss and duplicate effects. One durable setting cannot protect a different gap in the chain.

Keep any urgent safe valve action local when delivery is late. The chain can notify and retain evidence, but it must not be the sole route to stop immediate harm.

This opening does not promise exactly-once physical action. Practitioner maps each loss window and owner. Under the Hood examines confirms, durable definitions, stored bodies, worker replies, repeated delivery, dead-letter paths, and safe replay.

After this page, you should be able to:

  • Explain why publisher confirms, queue durability, message persistence, and consumer acknowledgments protect different loss windows.
  • Diagnose which reliability link is missing from an AMQP delivery path.
  • Explain why at-least-once delivery requires idempotent consumers.
  • Identify the exact broker triggers that dead-letter a message.
  • Design a DLX retry and parking flow that preserves investigation evidence.

10.8.2 Why This Follows AMQP Message Delivery

AMQP Message Delivery teaches message structure, delivery modes, publisher confirms, consumer acknowledgments, prefetch, dead-letter queues, and delivery sizing. This page tightens the contract that connects those pieces: no single flag makes delivery reliable, and each acknowledgment only means something inside its scope.

Use it when a deployment needs a zero-loss audit, when a durable queue still loses messages after restart, when repeated deliveries must be made safe with idempotency, or when a DLQ runbook needs to distinguish retryable failures from messages that should move to parking.

10.8.3 Overview: “Reliable” Is a Chain, Not a Switch

A message survives from producer to processed only if every link in a chain holds. There is no single “reliable” flag. At-least-once delivery end to end needs four independent mechanisms lined up:

  1. Publisher confirms so the producer knows the broker actually took the message.
  2. A durable queue so the queue definition survives a broker restart.
  3. A persistent message (delivery-mode = 2) so the message body is written to disk, not just held in RAM.
  4. Consumer acknowledgements so the broker only removes a message after it has been processed, not merely delivered.

Break any one and you open a silent loss window: no confirm means the producer never learns a publish was dropped; a non-durable queue vanishes on restart; a transient message in a durable queue is still lost on restart; auto-ack deletes a message the instant it is sent, before the consumer has done anything with it.

Concrete chain example: a gateway sends a valve-state alarm and keeps its local copy until the broker sends a publisher confirm. If the broker crashes before the confirm, the gateway resends from local storage. If the broker confirms and then restarts, the durable queue and persistent message are what make the alarm still appear after recovery. If the consumer receives the alarm, writes it to an incident table, and crashes before basic.ack, the broker requeues the unacknowledged delivery on channel close. That is why the downstream incident write needs an alarm id: the next consumer may see the same delivery again, and the database should treat it as the same alarm, not a second incident.

The practical audit question is therefore always, “where can the message be acknowledged but not yet recoverable?” Publisher confirms answer the producer side, persistence answers the broker restart side, and manual acknowledgements answer the consumer side. Treating those as one chain keeps operators from over-trusting a single durable setting.

10.8.5 Under the Hood: When a Message Is Dead-Lettered

A queue configured with x-dead-letter-exchange re-publishes a message to that exchange on exactly three triggers — nothing else:

  • the consumer rejects or nacks it with requeue=false (a poison message it cannot process),
  • the message’s TTL expires (a per-message expiration or the queue’s x-message-ttl), or
  • the queue overflows a length limit (x-max-length or x-max-length-bytes), which by default drops the oldest message.

On dead-lettering, the broker routes the message to the dead-letter exchange using x-dead-letter-routing-key if set, otherwise the message’s original routing key, and prepends an x-death header recording the reason, the source queue, a count, and a timestamp. That count is what lets a retry loop give up after N attempts instead of cycling a poison message forever. A common design is: main queue -> DLX -> a “retry” queue with a short TTL that dead-letters back to the main exchange, plus a “parking” queue for messages whose x-death count has exceeded the limit.

For example, a decoder that cannot parse a payload should send basic.nack(requeue=false), not keep requeueing the same poison message at the head of the main queue. The DLX can route it to a retry queue with x-message-ttl=30000; after 30 seconds that retry queue dead-letters it back to the main exchange. When the message fails again, the next x-death entry or count tells the retry policy it has already been through the loop. After three failed attempts, the handler can route it to a parking queue with the original body, headers, failure reason, and source queue preserved for investigation. The DLQ is therefore an evidence path as much as a reliability path: it stops one bad message from blocking good traffic while keeping enough context to repair the producer or consumer.

Inspect Figure 10.1 to separate a bounded retry loop from the terminal evidence path for a poison message.

AMQP DLX retry pattern: rejected, expired, or overflowed messages leave the main queue through a dead-letter exchange; retryable messages wait in a TTL retry queue and return to the main queue, while messages over the x-death limit go to a parking queue for investigation.
Figure 10.1: A dead-letter exchange is a controlled branch: retryable failures loop through a TTL queue, while messages over the retry limit move to a parking queue with their evidence intact.
  1. Broker Bex: Bex diverts one damaged parcel-shaped message from a moving main conveyor to a side gate.

    One message fails. Bex moves it off the main line.

  2. Broker Bex: Bex clips a reason card and one tally token to the same message.

    The broker saves why it failed and adds one count.

  3. Broker Bex: A short clock-lit side conveyor pauses, then returns the same marked message to the main line.

    A retry line waits, then sends the message back.

  4. Broker Bex: The same message returns to Bex with several tally tokens while good messages keep moving.

    It fails again. The saved count reaches the limit.

  5. Broker Bex: Bex places the message and its intact cards at an investigation desk, away from the clear main belt.

    Bex parks it with its evidence. Good work can pass.

CW-0006 walkthrough: A failed message leaves the main line, waits for a bounded retry, carries its failure count, and is parked with evidence when the limit is reached.

Trace Figure 10.1 from the main queue through rejection, expiry, or overflow into the dead-letter exchange. Retryable work waits in the TTL queue and returns; excessive failures move to parking with context intact. This route turns x-death history into a retry decision instead of an infinite cycle.

10.9 Summary

This chapter covered AMQP message structure and delivery guarantees:

First: Message Format: Analyzed header (durable, priority, TTL), properties (content-type, correlation-ID, message-ID), and body sections

Next: Delivery Modes: Compared at-most-once (fast, may lose), at-least-once (guaranteed, may duplicate), and exactly-once (no loss, no duplicates)

Then: Publisher Confirms: Implemented broker acknowledgment to producers for reliable publishing

After that: Consumer Acknowledgments: Applied manual ACK/NACK with prefetch control for processing guarantees

Also inspect: Dead Letter Queues: Configured DLQ for capturing failed messages for investigation

Finally: Idempotency: Used message-ID for deduplication in at-least-once scenarios

10.10 What’s Next

ChapterFocusWhy Read It
AMQP Frames and ReliabilitySASL authentication, TLS encryption, and AMQP 1.0 frame typesSecure and inspect the protocol layer that carries the messages you configured here
AMQP Core ArchitectureExchanges, queues, bindings, and the producer-broker-consumer modelReinforce how message routing decisions upstream affect the delivery guarantees you set
AMQP Implementations and LabsRabbitMQ broker setup, hands-on queue and DLQ configurationApply publisher confirms and DLQ patterns in a running broker environment
MQTT QoS LevelsMQTT at-most-once, at-least-once, and exactly-once equivalentsCompare AMQP delivery semantics with the constrained-device protocol used across most IoT edge devices
CoAP Fundamentals and ArchitectureRESTful CoAP reliability via CON/NON message typesContrast AMQP’s broker-mediated guarantees with CoAP’s direct endpoint reliability model
Protocol Integration PatternsBridging AMQP with MQTT, CoAP, and HTTP in IoT gatewaysSee how the delivery guarantees studied here propagate (or break) across protocol translation boundaries

10.11 Key Takeaway

Reliable AMQP delivery depends on explicit acknowledgement and redelivery behavior. Choose prefetch, acknowledgement timing, and dead-letter handling together so slow consumers do not turn into hidden message loss or unbounded backlog.

10.12 Continue Your Route

This final part closes the route from Worked Example: Smart Factory Message Sizing through Key Takeaway. Return to AMQP Delivery: Guarantees and Acknowledgements or continue from the amqp module index.