← Back to list

RabbitMQ Quorum Queues — A Simple Guide with Go (Beginner Friendly)

If you’ve used RabbitMQ before, you’re probably familiar with classic queues. They are simple, fast, and work well — until something goes…

Sarvesh Sharma · 2025-12-13 17:01 · 0 claps · 4.0 min read
#golang #rabbitmq #rabbitmq-cluster #kubernetes #event-driven-architecture
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud 🏛️ · Architecture

RabbitMQ Quorum Queues — A Simple Guide with Go (Beginner Friendly)

If you’ve used RabbitMQ before, you’re probably familiar with classic queues. They are simple, fast, and work well — until something goes wrong.

The moment a RabbitMQ node crashes, classic queues can lose messages. For systems that deal with payments, orders, or critical workflows, this is unacceptable.

This is exactly why Quorum Queues were introduced.

In this article, we’ll cover:

  • Why quorum queues exist
  • The problem they solve (in very simple terms)
  • How to deploy RabbitMQ in high availability (HA) mode using Kubernetes
  • How to create and use a quorum queue in Go
  • How to verify everything using the RabbitMQ Management UI

No deep RabbitMQ knowledge required. If you know basic messaging concepts, you’re good to go.

1. The Problem with Classic Queues

Let’s start with a simple scenario:

  1. A producer publishes a message
  2. RabbitMQ stores it on one node
  3. That node crashes 💥
  4. The message is gone ❌

This happens because classic queues live on a single node. Even if your RabbitMQ cluster has multiple nodes, a classic queue belongs to exactly one of them.

This behavior is risky for:

  • Payment processing systems
  • Order management systems
  • Event-driven workflows where data loss is unacceptable

You can mirror classic queues, but they are deprecated and come with their own operational issues.

So what’s the modern solution?

2. What Is a Quorum Queue?

A quorum queue is a replicated, fault-tolerant queue built on the Raft consensus algorithm.

In simple words:

  • Messages are stored on multiple RabbitMQ nodes
  • A majority of nodes must agree before a message is accepted
  • The queue continues working even if a node crashes

Example

If you have 3 RabbitMQ nodes:

  • At least 2 nodes must be alive (majority)
  • If 1 node crashes, messages are still safe ✅
  • If 2 nodes crash, the queue becomes unavailable (no majority)

You can think of quorum queues as distributed consensus for messages.

Reliability over raw speed — that’s the tradeoff quorum queues make.

3. Running RabbitMQ in HA Mode (Kubernetes)

To use quorum queues properly, you need a RabbitMQ cluster.

The easiest way to run RabbitMQ in Kubernetes is by using the RabbitMQ Cluster Operator.

Step 1: Install the RabbitMQ Cluster Operator

kubectl apply -f "https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml"

This installs all the required CRDs and controllers.

Step 2: Create a RabbitMQ Cluster

Create a file called cluster.yaml:

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: rabbitmqcluster
spec:
  replicas: 3
  resources:
    requests:
      cpu: 500m
      memory: 2Gi
    limits:
      cpu: 700m
      memory: 2Gi
  persistence:
    storage: 1Gi

Apply it:

kubectl apply -f cluster.yaml

What Happens After Deployment?

  • Kubernetes creates 3 RabbitMQ pods

  • Each pod runs a RabbitMQ broker
  • When you create a quorum queue
  • One node is elected as the leader
  • Other nodes act as followers (replicas)

When a message is published:

  1. The leader receives the message
  2. The message is replicated to follower nodes
  3. Once a majority confirms, the message is accepted

If the leader crashes:

  • One of the followers becomes the new leader
  • The queue continues serving requests

This guarantees high availability and data safety.

4. Creating a Quorum Queue in Go

Now let’s write a simple Go program that:

  • Connects to RabbitMQ
  • Creates an exchange
  • Creates a quorum queue
  • Publishes a message
  • Consumes the message

We’ll use the official Go client:

go get github.com/rabbitmq/amqp091-go

Step 1: Connect to RabbitMQ

url := "amqp://username:password@localhost:5672/"
conn, err := amqp091.Dial(url)
if err != nil {
    panic(err)
}
defer conn.Close()
ch, err := conn.Channel()
if err != nil {
    panic(err)
}
defer ch.Close()

This establishes a connection and opens a channel.

Step 2: Declare an Exchange

err = ch.ExchangeDeclare(
    "quorum-exchange",
    "direct",
    true,  
    false, 
    false,
    false,
    nil,
)
if err != nil {
    panic(err)
}

This creates a durable direct exchange.

Step 3: Declare a Quorum Queue (Important Part)

This is the only difference compared to a classic queue.

_, err = ch.QueueDeclare(
    "quorum-q",
    true,
    false,
    false,
    false,
    amqp091.Table{
        "x-queue-type": amqp091.QueueTypeQuorum,
    },
)
if err != nil {
    panic(err)
}

📌 Important Notes

  • Queue type must be defined at creation time
  • A classic queue cannot be converted to a quorum queue later

Step 4: Bind Queue to Exchange

err = ch.QueueBind(
    "quorum-q",
    "rk",
    "quorum-exchange",
    false,
    nil,
)
if err != nil {
    panic(err)
}

Step 5: Publish a Message

err = ch.PublishWithContext(
    context.Background(),
    "quorum-exchange",
    "rk",
    false,
    false,
    amqp091.Publishing{
        ContentType: "text/plain",
        Body:        []byte("message"),
    },
)
if err != nil {
    panic(err)
}

Step 6: Consume the Message

msgs, err := ch.Consume(
    "quorum-q",
    "consumer",
    false,
    false,
    false,
    false,
    nil,
)
if err != nil {
    panic(err)
}
for msg := range msgs {
    fmt.Printf("message from queue: %s\n", string(msg.Body))
    msg.Ack(false)
}

Using manual acknowledgements ensures:

  • Messages aren’t lost if the consumer crashes
  • Messages are re-delivered if processing fails

5. Full Working Example

package main

import (
    "context"
    "fmt"
    "github.com/rabbitmq/amqp091-go"
)

func main() {
    url := "amqp://username:password@localhost:5672/"
    conn, err := amqp091.Dial(url)
    if err != nil {
        panic(err)
    }
    defer conn.Close()
    ch, err := conn.Channel()
    if err != nil {
        panic(err)
    }
    defer ch.Close()
    err = ch.ExchangeDeclare(
        "quorum-exchange",
        "direct",
        true,
        false,
        false,
        false,
        nil,
    )
    if err != nil {
        panic(err)
    }
    _, err = ch.QueueDeclare(
        "quorum-q",
        true,
        false,
        false,
        false,
        amqp091.Table{
            "x-queue-type": amqp091.QueueTypeQuorum,
        },
    )
    if err != nil {
        panic(err)
    }
    err = ch.QueueBind(
        "quorum-q",
        "rk",
        "quorum-exchange",
        false,
        nil,
    )
    if err != nil {
        panic(err)
    }
    err = ch.PublishWithContext(
        context.Background(),
        "quorum-exchange",
        "rk",
        false,
        false,
        amqp091.Publishing{
            ContentType: "text/plain",
            Body:        []byte("message"),
        },
    )
    if err != nil {
        panic(err)
    }
    msgs, err := ch.Consume(
        "quorum-q",
        "consumer",
        false,
        false,
        false,
        false,
        nil,
    )
    if err != nil {
        panic(err)
    }
    for msg := range msgs {
        fmt.Printf("message from queue: %s\n", string(msg.Body))
        msg.Ack(false)
    }
}

Final Thoughts

Quorum queues are the recommended choice for:

  • Mission-critical messaging
  • Distributed systems
  • Production workloads where data loss is unacceptable

They trade a bit of throughput for strong consistency and fault tolerance — a tradeoff that is usually worth it.

If you’re building serious systems with RabbitMQ today, quorum queues should be your default choice.

Happy messaging 🚀


메타데이터
post_id
7c6473d8bf10
slug
rabbitmq-quorum-queues-a-simple-guide-with-go-beginner-friendly-7c6473d8bf10
url
https://medium.com/@sharmasarvesh826/rabbitmq-quorum-queues-a-simple-guide-with-go-beginner-friendly-7c6473d8bf10
canonical_url
https://medium.com/@sharmasarvesh826/rabbitmq-quorum-queues-a-simple-guide-with-go-beginner-friendly-7c6473d8bf10
author_url
https://medium.com/@sharmasarvesh826
status
ok
fetched_at
2026-06-09 15:37:30