All Articles

Rabbit MQ

ActiveMQ vs RabbitMQ vs Kafka

Feature ActiveMQ RabbitMQ Kafka
Architecture JMS-based, supports multiple protocols AMQP-based, optimized for AMQP Distributed log-based system
Performance Moderate throughput High throughput Extremely high throughput
Use Case Legacy enterprise systems, JMS-based applications Cloud-native apps, microservices, real-time messaging Event streaming, real-time analytics, log aggregation
Protocol Support Supports JMS, AMQP, MQTT, STOMP, etc. Primarily AMQP, with plugins for others Custom protocol, optimized for streaming
Ease of Use More complex setup Easier to set up and configure Requires more setup and expertise
Scalability Moderate scalability High scalability with clustering Horizontally scalable, designed for distributed systems
Message Ordering Supports message ordering Supports message ordering Strong ordering guarantees
Durability Persistent messages supported Persistent messages supported Highly durable with replication
Plugins and Extensibility Limited plugin ecosystem Rich plugin ecosystem Limited plugins, but highly extensible
Community and Ecosystem Smaller community, fewer integrations Larger community, extensive integrations Large community, strong ecosystem
Best For Traditional enterprise systems Modern cloud-native applications Event-driven architectures, big data

When to Use:

  • ActiveMQ: Best suited for traditional enterprise systems, legacy JMS-based applications, and use cases requiring multiple protocol support.
  • RabbitMQ: Ideal for modern cloud-native applications, microservices, real-time messaging, and scenarios requiring high throughput.
  • Kafka: Designed for event-driven architectures, big data pipelines, real-time analytics, and scenarios requiring extremely high throughput and durability.

RabbitMQ is not popular anymore, we usually choose Kafka for large systems or choose a queue within cloud we use like Google pub/sub if you’re using GCP (Google Cloud Platform) or Amazon Simple Queue Service (SQS).

Today we will learn about rabbitMQ to know basis about how a queue works

  1. Producer (Provider Service)
    • Sends messages to an exchange in RabbitMQ.
    • Uses direct, topic, fanout, or headers exchanges depending on routing needs.
  2. Broker (RabbitMQ Server)
    • Routes messages to queues based on exchange type.
  3. Consumer (Public Subscriber)
    • Listens to queues and processes messages.
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

docker-compose.yml

services:
  rabbitmq:
    image: rabbitmq:3.12-management  # Includes the web management UI
    container_name: rabbitmq
    restart: always
    environment:
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: admin
    ports:
      - "5672:5672"   # AMQP protocol port
      - "15672:15672" # Management UI port
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq  # Persist RabbitMQ data

volumes:
  rabbitmq_data:
    driver: local
docker-compose up -d

In order to access web, using port 15672, http://localhost:15672

RabbitMQ Exchange types

RabbitMQ supports four main types of exchanges: Direct, Fanout, Topic, and Headers.

Exchange Type When to Use
Direct Specific routing based on exact keys.
Fanout Broadcast to multiple consumers.
Topic Pattern-based routing (e.g., logs, multi-level keys).
Headers Advanced routing with custom attributes.

1. Direct Exchange (direct)

Routes messages to queues with an exact matching routing key

  • Create a new queue: error_queue
  • Create a new direct exchange: direct_exchange
  • In direct_exchange, add binding to error_queue with routing key: error
  • Write code to send message to direct_exchange
  • Write code to receive message from error_queue queue

error_queue direct_exchange binding direct_exchange to error_queue

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    public static final String QUEUE_NAME = "error_queue";
    public static final String EXCHANGE_NAME = "direct_exchange";
    public static final String ROUTING_KEY = "error";
}
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(String message) {
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, RabbitMQConfig.ROUTING_KEY, message);        
    }
}

error_queue ready

2. Fanout Exchange (fanout)

Broadcasts messages to all bound queues, ignoring routing keys.

  • Create 2 new queues: log_queue_1, log_queue_2
  • Create a new fanout exchange: log_exchange
  • In log_exchange, add binding to log_queue_1, log_queue_2
  • Write code to send message to log_exchange
  • Write code to receive message from log_queue_1 and log_queue_2 queues

log_exchange binding

rabbitTemplate.convertAndSend("log_exchange", "", message);

log_queue_1 messages

3. Topic Exchange (topic)

Routes messages based on pattern matching in routing keys using:

  • * → Matches one word.
  • # → Matches multiple words.

Create 2 queues: app1_logs, app2_log

Create topic exchange: logs_topic

In logs_topic, create 2 binding to 2 queues

  1. binding 1:
    • to queue: app1_log
    • routing key: logs.error.app1
  2. binding 2:
    • to queue: app2_log
    • routing key: logs.info.app2

Send message to logs_topic with routing key: logs.*.app1

Only app1_log queue receive message.

4. Headers Exchange (headers)

Uses message headers (instead of routing keys) for routing.

  • Create a queue: pdf_logs
  • Create header exchange: logs_headers
    • format = pdf
  • Send message to logs_headers with headers: {format: "pdf", type: "report" }

logs_header binding

public void sendHeadersMessage() {
    MessageProperties messageProperties = new MessageProperties();
    messageProperties.setHeader("format", "pdf");
    messageProperties.setHeader("type", "report");

    Message msg = new Message("Here is a headers message".getBytes(StandardCharsets.UTF_8), messageProperties);
    rabbitTemplate.send("logs_headers", "", msg); // Headers exchange ignores routing keys        
}

log_queue_1 messages

Published Mar 26, 2025

☕ Coffee addict, 👩‍💻 System Design