interviewDeck

Your one-stop platform to prepare, practice and ace your interviews.

Loading your questions…

All Questions

Filters & tools

RabbitMQ Interview Questions and Answers

19 hand-picked RabbitMQ interview questions with detailed answers. Open the interactive version above to search, filter by difficulty, run code, bookmark questions and track your progress.

What is RabbitMQ and what is AMQP?

RabbitMQ is an open-source message broker implementing the AMQP 0-9-1 protocol. It receives messages from producers, routes them through exchanges to queues, and delivers them to consumers.

Core value: decoupling services — producers don't need to know about consumers, enabling async processing, load levelling, and reliable delivery.

Explain exchanges, queues, bindings, and routing keys.

Message flow: ProducerExchange → (binding) → QueueConsumer

  • Exchange — receives messages and routes to queues based on rules.
  • Queue — stores messages until consumed (FIFO).
  • Binding — link between exchange and queue with a routing key pattern.
  • Routing key — attribute on the message used by the exchange for routing decisions.

Direct vs fanout vs topic vs headers exchanges.

  • Direct — routing key must exactly match binding key. One-to-one or one-to-few. Example: task dispatch by type.
  • Fanout — ignores routing key; broadcasts to all bound queues. Example: cache invalidation notifications.
  • Topic — routing key matched against binding pattern with * and # wildcards. Example: event bus (order.created, user.deleted).
  • Headers — routes based on message header attributes. Rarely used; more flexible but slower.

What are acknowledgments and why do they matter?

Publisher confirms — broker acks that it received the message from the producer.

Consumer acknowledgments — consumer tells broker it successfully processed the message. Until acked, the message stays in the queue (or is redelivered on disconnect).

  • Manual ack (basicAck) — ack after processing. Safe but consumer must not forget.
  • Auto ack — broker acks on delivery, before processing. Risk: message lost if consumer crashes mid-processing.
  • Nack / reject — negative ack; requeue or send to dead letter.
channel.basicConsume(queue, false, (tag, delivery) -> {
  try {
    process(delivery.getBody());
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  } catch (Exception e) {
    channel.basicNack(delivery.getEnvelope().getDeliveryTag(), false, true);
  }
}, tag -> {});

What is prefetch (QoS) and how do you tune it?

basicQos(prefetchCount) limits how many unacknowledged messages a consumer can hold at once. Default: unlimited (broker pushes all messages to consumer).

Low prefetch (1–10): fair distribution across consumers, slower throughput. High prefetch (50–100): better throughput but one slow consumer hoards messages.

Set per-channel: channel.basicQos(10) — each consumer gets max 10 unacked messages.

channel.basicQos(10);  // max 10 unacked messages per consumer

How do you make messages and queues survive broker restarts?

Three things must be durable:

  1. Durable queuequeueDeclare(name, durable=true, ...). Survives broker restart.
  2. Persistent messagesdeliveryMode=2 (or MessageProperties.PERSISTENT_TEXT_PLAIN). Written to disk.
  3. Durable exchange — survives restart (default for most types).

Non-durable queues and transient messages are lost on restart — fine for ephemeral tasks.

channel.queueDeclare("orders", true, false, false, null);
channel.basicPublish("", "orders",
  MessageProperties.PERSISTENT_TEXT_PLAIN, body);

What is a Dead Letter Exchange (DLX)?

Messages that are rejected (nack without requeue), expire (TTL exceeded), or exceed queue length limit are routed to a Dead Letter Exchange, which forwards them to a dead letter queue for inspection.

Configure on the original queue: x-dead-letter-exchange and x-dead-letter-routing-key.

Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx");
channel.queueDeclare("orders", true, false, false, args);

Message TTL and queue TTL.

Per-message TTL — set expiration property (milliseconds as string). Message is discarded or dead-lettered after TTL expires (even if sitting in queue unprocessed).

Per-queue TTLx-message-ttl argument on queue declaration. Applies to all messages in the queue.

Use cases: time-sensitive notifications, retry delays, cache-like behaviour.

AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
  .expiration("60000")  // 60 seconds
  .build();

RabbitMQ vs Kafka — when to use each?

See Kafka category for full table. Summary:

  • RabbitMQ — complex routing, task queues, request-reply, moderate throughput, messages deleted after ack. Like a post office with smart sorting.
  • Kafka — high-throughput event streaming, message replay, log retention, simple routing. Like a newspaper printing press.

Many systems use both: RabbitMQ for task dispatch, Kafka for event streaming.

How does the RPC (request-reply) pattern work in RabbitMQ?

Client sends a message with two special properties:

  • replyTo — name of a temporary callback queue.
  • correlationId — matches request to response.

Server processes the request and publishes the response to the replyTo queue with the same correlationId. Client correlates and returns the result.

Built into Spring AMQP's RabbitTemplate.convertSendAndReceive().

Object response = rabbitTemplate.convertSendAndReceive("rpc-queue", request);

RabbitMQ clustering and high availability.

Clustering — multiple RabbitMQ nodes share metadata (exchanges, queues, bindings). Queues live on one node (master) but can be mirrored.

Classic mirrored queues — copies on multiple nodes (deprecated). Quorum queues — Raft-based replication (recommended). Survive node failures with automatic leader election.

For multi-datacenter: Federation or Shovel plugins replicate messages between independent brokers.

Map<String, Object> args = Map.of("x-queue-type", "quorum");
channel.queueDeclare("orders", true, false, false, args);

Using RabbitMQ with Spring Boot (Spring AMQP).

spring-boot-starter-amqp provides:

  • @RabbitListener(queues = "orders") — declarative consumer.
  • RabbitTemplate — send messages.
  • @Bean Queue/Exchange/Binding — declare topology in code.
  • Auto-config from spring.rabbitmq.* properties.
  • Retry with @Retryable or RetryInterceptorBuilder.
@RabbitListener(queues = "orders")
public void handle(Order order) {
  orderService.process(order);
}

How do you handle poison messages?

A poison message always fails processing — infinite requeue loop blocks the consumer. Solutions:

  • Retry limit — track retry count in message headers; after N failures, nack without requeue → DLX.
  • DLX to parking lot — dead letter queue for manual inspection.
  • Skip and log — ack the message, log the error (data loss).

Spring AMQP: ConditionalRejectingErrorHandler + FatalExceptionStrategy.

Connection vs channel in RabbitMQ.

Connection — TCP connection to the broker (expensive to create). Use a connection pool; one per app instance is typical.

Channel — lightweight virtual connection inside a TCP connection. Most operations (publish, consume, declare) happen on channels. Create a channel per thread; channels are not thread-safe.

Pattern: one Connection (shared), one Channel per consumer thread.

Connection conn = factory.newConnection();
Channel channel = conn.createChannel();  // one per thread

How do priority queues work?

Declare queue with x-max-priority (e.g. 10). Set priority (0–10) on messages. Higher priority messages are delivered before lower ones in the queue.

Use for: urgent notifications, VIP task processing. Not a replacement for separate queues — priority only works among messages already in the same queue.

args.put("x-max-priority", 10);
channel.queueDeclare("tasks", true, false, false, args);

What is the work queue (competing consumers) pattern?

Multiple consumers listen to the same queue. RabbitMQ distributes messages round-robin among consumers — each message goes to exactly one consumer. Enables load levelling: burst of tasks spread across workers.

Combine with prefetch for fair dispatch. Add more consumers to scale throughput (up to the queue's capacity).

How do you implement pub/sub in RabbitMQ?

Use a fanout exchange. Each consumer creates its own exclusive, auto-delete queue bound to the fanout exchange. Every message published to the fanout goes to all bound queues — each subscriber gets a copy.

Unlike work queues (one consumer per message), pub/sub delivers to every subscriber.

channel.exchangeDeclare("events", "fanout");
String queueName = channel.queueDeclare().getQueue();  // auto-named, exclusive
channel.queueBind(queueName, "events", "");

How do you monitor RabbitMQ?

Management UI — built-in web UI (port 15672) showing queues, rates, connections, consumers.

Key metrics:

  • Queue depth — messages ready + unacked. Growing = consumers can't keep up.
  • Publish/deliver rates — throughput.
  • Consumer utilisation — are consumers busy or idle?
  • Memory/disk alarms — broker blocks publishers when resources are low.

Prometheus plugin for Grafana dashboards. Alert on queue depth thresholds.

Best practices for message size and content.

RabbitMQ handles small messages (KB) best. For large payloads:

  • Store the data elsewhere (S3, DB) and send a reference (URL/ID) in the message.
  • Default max message size is 128MB but large messages hurt performance and memory.
  • Keep messages serialisable (JSON, Avro, Protobuf) — avoid sending non-serialisable objects.
  • Include correlation ID, timestamp, and content-type in message properties.