Skip to content
Knowledge Hub

Messaging Basic

Kafka is a log with read positions: reading does not delete records, many groups read independently, and data can be replayed. RabbitMQ is a router plus queues: the exchange decides which queues receive a message, and once acked the message leaves the queue.

The two models answer three questions differently: does a message still exist after it is read, who decides where a message goes, and what “sent successfully” means.

Need Choose Why
Replay, many independent consumers reading the same data Kafka The log is kept per retention, each group has its own offset
Per-key ordering at high throughput Kafka Ordering within a partition, the key picks the partition
Event streaming, CDC, stream processing Kafka Connect, Streams, compaction ecosystem
Work queue, one worker per job, per-job ack RabbitMQ (quorum queue) Per-message ack, DLX, prefetch
Flexible pattern-based routing (topic, headers) RabbitMQ Exchanges and bindings
Retry with backoff, per-message dead-lettering RabbitMQ DLX, TTL, x-delivery-limit
Need both queue-like and log semantics in one system Consider Kafka Share Groups (4.2) or RabbitMQ streams See Share Groups and queue types

Rule of thumb: need replay or streaming, use Kafka; need work distribution and routing, use RabbitMQ. Both are at-least-once at the application level, so an idempotent consumer is always needed.

Article Answers the question
Exchanges and bindings Which queue does a message reach? Does an error-free publish mean it reached a queue?
Ack, prefetch, publisher confirms How do the three acknowledgment boundaries differ? What is consumer_timeout?
Dead-lettering, TTL, counted retries Where do failed jobs go, how many retries, where does a poison message stop?
Classic, quorum, stream Which queue type for each flow?

The broker manages messages and delivery state; it does not know whether the service’s side effect succeeded. Write to the database, then crash before acknowledging, and the message is processed again; acknowledge before writing, and the work is lost.

Handling duplicates

Idempotent consumer: inbox table, unique key, one transaction. Works for both Kafka and RabbitMQ.

Dual write

Transactional outbox: write state and the intent to publish an event in one DB transaction. Prevents lost events; duplicates are still possible.

Broader context: the eight fallacies of distributed computing.

Situation Read in this order
New to Kafka Distributed log → Message key → Consumer group
New to RabbitMQ Exchange → Ack and prefetch → DLX and TTL
An event is processed twice Idempotent consumer → Offset commit
The producer reported success but data was lost Replication, ISR, acks
Adding consumers does not raise throughput Share Groups
Need to replay but the data is gone Retention and compaction
Lag is rising for unknown reasons Consumer lag → Consumer group
One failing message blocks a whole Kafka partition Retry topics and DLQ → Idempotent consumer
RabbitMQ queue is full, jobs loop forever Dead-lettering and counted retries
DB committed but the event never reached the broker Transactional outbox
A producer changed the event shape and an older consumer broke Event schema evolution