← Back to blog

Message Queue Selection: RabbitMQ vs Kafka vs Redis Streams

Message queue selection is not about "picking the most popular one" — it is about "picking the one that fits your scenario." This article compares RabbitMQ, Kafka, and Redis Streams across message model, persistence, throughput, and consumption patterns — for backend architects and tech leads evaluating or selecting a message queue solution.

The Bottom Line: There Is No Best Message Queue — Only the Best Fit

Message queue selection is one of the most trend-driven technical decisions. Kafka is popular, so use Kafka. RabbitMQ is stable, so use RabbitMQ. Redis Streams is simple, so use Redis Streams. But the wrong choice leads to high operational costs down the road.


1. Core Comparison

DimensionRabbitMQKafkaRedis Streams
Message modelQueue (consume and delete)Log (read by offset)Stream (read by ID)
ThroughputTens of thousands/secMillions/secHundreds of thousands/sec
PersistenceDisk + optional memoryDisk (sequential writes)Disk (RDB/AOF)
ConsumptionCompeting consumersConsumer groupsConsumer groups
Message replayNot supportedSupported (by offset)Supported (by ID)
Ops complexityMediumHigh (needs ZooKeeper)Low (no extra components)
Best forTask distribution, RPCEvent streams, log aggregationLightweight queues, real-time data

2. Decision Tree

Need a message queue?
├── High throughput (millions/sec)?
│   ├── Yes → Kafka
│   └── No ↓
├── Need message replay/rewind?
│   ├── Yes → Kafka
│   └── No ↓
├── Need complex routing (Topic → Exchange → Queue)?
│   ├── Yes → RabbitMQ
│   └── No ↓
├── Already using Redis, no new components?
│   ├── Yes → Redis Streams
│   └── No → RabbitMQ (default recommendation)

3. Message Reliability Configuration

RabbitMQ Reliable Config

const channel = await connection.createConfirmChannel();
await channel.publish('exchange', 'routingKey', content, { persistent: true });
await channel.waitForConfirms();

channel.consume('queue', (msg) => {
  try {
    process(msg);
    channel.ack(msg);
  } catch (err) {
    channel.nack(msg, false, true);
  }
}, { noAck: false });

Kafka Reliable Config

const producer = new KafkaProducer({
  acks: 'all',
  retries: 3,
});

consumer.run({
  eachMessage: async ({ message }) => {
    await process(message);
    await consumer.commitOffsets([{ topic, partition, offset: message.offset + 1 }]);
  },
});

4. Scenario Recommendations

ScenarioRecommendedReason
Task queue (one message, one consumer)RabbitMQQueue model fits naturally
Event stream (one message, multiple consumers)KafkaLog model supports multiple consumers
Log aggregationKafkaHigh throughput + message persistence
Real-time notifications (WebSocket push)Redis StreamsLow latency + simple deployment
Microservice async communicationRabbitMQFlexible routing + mature stability
Data pipeline (ETL)KafkaHigh throughput + message replay

Summary

DimensionRabbitMQKafkaRedis Streams
Learning curveMediumHighLow
Ops costMediumHighLow
ThroughputTens of thousandsMillionsHundreds of thousands
Message persistenceSupportedSupportedSupported
Message replayNot supportedSupportedSupported
Best forTask distribution, microservicesEvent streams, logsLightweight queues

Message queue selection is not about “picking the best one” — it is about “picking the least bad one.” Each solution has trade-offs. The key is understanding your scenario requirements for throughput, reliability, and message model, then choosing the one that is “least bad” across those dimensions.

Need message queue design or backend architecture consulting? Contact us — tell us about your communication scenario and scale, feasibility within 24 hours.

FAQ

What is the core difference between RabbitMQ and Kafka?

The message model. RabbitMQ uses a "queue model" — a message is consumed and deleted from the queue. Kafka uses a "log model" — messages are appended to partition logs, and consumers read by offset. Messages are not deleted after consumption and can be replayed. This determines their use cases: RabbitMQ is for task distribution (each message processed once), Kafka is for event streams (each message consumed by multiple consumers).

Can Redis Streams replace RabbitMQ or Kafka?

Depends on the scenario. Redis Streams is simpler — no need for additional message queue cluster deployment. Suitable for lightweight scenarios (task queues, simple pub/sub). But for message persistence, high throughput (millions/sec), message replay, and partition scaling, RabbitMQ or Kafka are more appropriate. Redis Streams is not a replacement — it is a lightweight choice for scenarios that do not need the heavier solutions.

Can messages be lost in a message queue?

Yes, depending on configuration. Messages can be lost at three points: ① Producer → Broker — enable Publisher Confirms to ensure message arrival; ② Broker storage — enable message persistence (disk writes) and mirrored queues/replicas; ③ Consumer consumption — use manual acknowledgment (Manual Ack), not auto-ack. With all three configured correctly, message loss probability is very low but not zero.

How do you determine Kafka partition count?

Partition count = max(target throughput / single partition throughput, consumer count). A single Kafka partition handles approximately 10-20 MB/s. If you need 100 MB/s throughput, you need at least 5-10 partitions. But do not set too many partitions blindly — more partitions increase ZooKeeper load and Leader election time. Recommended initial setting: 3-6 partitions, adjust based on actual load.

This article comes from AI Enable Harness front-line delivery practice. Need a similar system or optimization service?

Subscribe to Updates

Get notified when new articles are published. No spam, occasional updates only.

Subscribe →