Message Queues: Kafka vs RabbitMQ vs SQS
mediumMessage queues decouple producers and consumers so work can be done asynchronously, retried on failure, distributed across workers, and absorbed in bursts. The category splits into two architectures with very different properties.
Key Concepts
user_id, order_id) so they land on one partition. Global ordering = single partition = no parallelism = throughput ceiling of one node. Don't promise it.Approach
- Pick the family. Log-based (Kafka, Pulsar) for events, replay, multi-consumer. Queue (RabbitMQ, SQS) for task distribution.
- Partition for throughput. Kafka: hash by routing key. SQS FIFO: MessageGroupId. RabbitMQ: multiple queues with consistent-hash exchange.
- Choose delivery semantics. Default at-least-once + idempotent consumers. Exactly-once only when truly needed.
- Plan for poison messages: DLQ with explicit replay tooling.
- Schema discipline: Avro/Protobuf + registry; semver compatibility rules.
- Producer config: batching, compression (Snappy/LZ4), acks=all for durability.
- Consumer config: explicit commit on success; commit interval tuned for at-least-once.
- Monitor lag: messages-behind-head per consumer group; alert when lag grows.
Family-by-family
Kafka: append-only partitioned log. Consumers track offsets. Pull-based. Retention configurable. Strong throughput. Operationally heavy (ZooKeeper or KRaft). Used at LinkedIn, Netflix, Uber.
Pulsar: like Kafka but with multi-tenancy, tiered storage, separated compute/storage. Used at Yahoo, Tencent.
RabbitMQ: queues with rich routing (exchanges, bindings). Push-based delivery, ack/nack semantics. Strong for task queues. Smaller scale than Kafka.
SQS: fully managed, no ordering (standard) or limited ordering (FIFO). No replay. Easy to operate. Use SNS+SQS for fanout.
NATS JetStream: newer, lightweight, good defaults. Strong for microservices messaging.
Components
- Producers with idempotency keys, batching, compression.
- Broker cluster with replicated partitions (Kafka: ISR-based replication).
- Consumer groups with rebalance protocol.
- Schema registry (Avro, Protobuf).
- DLQ + retry topic for poison messages.
- Lag monitoring + autoscaling consumers.
- Connectors — sinks to S3, Elasticsearch, JDBC; sources from CDC.
Trade-offs
Kafka: highest throughput, replay, ordering per key. Operational complexity is real (ZK/KRaft, brokers, partitions, retention, compaction).
RabbitMQ: rich routing, simpler ops, smaller scale.
SQS: simplest, fully managed. No replay, limited ordering.
Exactly-once: achievable in Kafka but expensive. Idempotency at the consumer is the pragmatic alternative.
Global ordering = no parallelism. Don't promise it. Design ordering as a per-key property.
Retention vs cost: longer retention enables replay and audit; consumes disk.
Common pitfalls
- Treating SQS like Kafka. SQS doesn't replay.
- Using a single partition for ordering — that's a throughput ceiling of one node.
- Forgetting DLQ — poison messages wedge consumers permanently.
- Letting consumer lag grow indefinitely — eventually retention drops the unread messages.
- No schema discipline — one bad producer change breaks every consumer.
- Manual offset management — let the consumer library handle it unless you have a very good reason.