Steven's Knowledge

Message Queues

Asynchronous messaging systems for decoupled, scalable architectures - from your first producer to picking the right broker

Message Queues

Message queues let producers and consumers communicate asynchronously. The producer hands a message to the broker and moves on; the consumer reads it whenever it's ready. This decoupling is the foundation of event-driven systems, task pipelines, and most microservice architectures.

Why Use One

Without a queueWith a queue
Service A calls B directly; if B is slow, A blocksA enqueues, B processes at its own pace
If B is down, A's request failsThe message waits in the queue
Adding a third consumer requires A to know about itMultiple consumers subscribe; A doesn't change
Bursts overwhelm BThe queue absorbs the burst
Retries / dead-letter handling reinvented per call siteThe broker provides it once

Two Mental Models

There are dozens of message systems, but they cluster into two camps:

The Distributed Log (Kafka)

Producer ──► Topic (partition 0) [m1, m2, m3, m4, m5, m6, ...] ──► Consumer Group A
                                                                ├─► Consumer Group B
         ──► Topic (partition 1) [m1, m2, m3, m4, m5, m6, ...] ──► Consumer Group A
                                                                └─► Consumer Group B

Messages are appended to a partitioned log and retained. Consumers track their own position. Multiple consumer groups can read the same messages independently. Replay is built in.

The Message Broker (RabbitMQ)

Producer ──► Exchange ──┬── binding ──► Queue 1 ──► Consumer A
                        ├── binding ──► Queue 2 ──► Consumer B
                        └── binding ──► Queue 3 ──► Consumer C

Messages are routed from exchanges into queues; a consumer takes a message off a queue and acknowledges it; the message is then gone. Flexible routing, but no replay.

The Players

SystemModelStrengthWhen to consider
Apache KafkaDistributed logThroughput, retention, replayEvent streaming, log pipelines, ≥100K msg/s
RabbitMQAMQP brokerRouting flexibility, low latencyTask queues, RPC, complex routing
Redis StreamsIn-memory logSpeed, simplicityLightweight messaging when you already run Redis
AWS SQSManaged queueZero opsSimple decoupled cloud workloads
NATSCloud-native pub/subLightweight, very fastMicroservice signalling, request/reply
PulsarHybrid (log + queue)Tiered storage, multi-tenancyWant both Kafka and RabbitMQ semantics

Learning Path

Read in this order if you're new — each page builds on the previous one.

Concerns That Apply to Every Broker

No matter which system you pick, the same questions come up:

ConcernWhat to think about
Delivery semanticsAt-most-once, at-least-once, exactly-once — pick consciously
OrderingMost systems guarantee ordering only within a partition / queue
Idempotent consumersNetworks fail; you'll see the same message twice — design for it
BackpressureWhat happens when consumers fall behind? Slow producers? Drop? Spool to disk?
Dead-letter handlingWhere do "poison" messages that always fail go?
SchemasAvro / Protobuf / JSON-Schema — agree before producers and consumers diverge
ObservabilityLag, throughput, error rate — instrument every producer and consumer

Message queues sit between services that would otherwise call each other directly. If you need real-time request/response (synchronous, blocking, with a single answer), a queue isn't the right tool — use an HTTP/gRPC call. Queues shine when "I'll get to it eventually" is acceptable.

On this page