Mirror RabbitMQ queues cluster to replicate configuration across multiple nodes.

Preliminary information

I will use RabbitMQ cluster consisting of node: rabbit, reindeer and raccoon.

Mirror RabbitMQ queues

Get rabbitmqadmin utility.

$ curl -o rabbitmqadmin http://127.0.0.1:15672/cli/rabbitmqadmin

Ensure that executable bit is set.

$ chmod +x rabbitmqadmin

Declare mirror_example vhost.

$ ./rabbitmqadmin --username admin --password password declare vhost name=mirror_example

Declare mirror_example user with password password, grant permissions to mirror_example vhost and set administrator.

$ sudo rabbitmqctl add_user mirror_example password
$ sudo rabbitmqctl set_permissions mirror_example --vhost mirror_example ".*" ".*" ".*"
$ sudo rabbitmqctl set_user_tags mirror_example administrator

Define mirror-all policy that will mirror every queue with name that begins with mirror-all to every node.

$ sudo rabbitmqctl set_policy -p mirror_example mirror-all "^mirror-all.*" '{"ha-mode": "all", "ha-sync-mode":"automatic"}'

Define mirror-exactly policy that will mirror every queue with name that begins with mirror-exactly to one additional node.

$ sudo rabbitmqctl set_policy -p mirror_example mirror-exactly "^mirror-exactly.*" '{"ha-mode": "exactly", "ha-params":2, "ha-sync-mode":"automatic"}'

Define mirror-nodes policy that will keep every queue with name that begins with mirror-nodes on two specified nodes.

$ sudo rabbitmqctl set_policy -p mirror_example mirror-nodes "^mirror-nodes.*" '{"ha-mode": "nodes", "ha-params": ["rabbit@reindeer", "rabbit@raccoon"], "ha-sync-mode":"automatic"}'

Display declared policies.

$ sudo rabbitmqctl list_policies -p mirror_example
Listing policies for vhost "mirror_example" ...
vhost           name            pattern                 apply-to  definition                                                                                         priority
mirror_example  mirror-nodes    ^mirror-nodes.*         all       {"ha-mode":"nodes","ha-params":["rabbit@reindeer","rabbit@raccoon"],"ha-sync-mode":"automatic"}    0
mirror_example  mirror-exactly  ^mirror-exactly.*       all       {"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}                                     0
mirror_example  mirror-all      ^mirror-all.*           all       {"ha-mode":"all","ha-sync-mode":"automatic"}                                                       0

Declare sample exchange.

$ ./rabbitmqadmin --username mirror_example --password password --vhost mirror_example declare exchange name=messages type=fanout

Declare mirror-all.messages queue.

$ ./rabbitmqadmin --username mirror_example --password password --vhost mirror_example declare queue name=mirror-all.messages durable=true

Declare mirror-exactly.messages queue.

$ ./rabbitmqadmin --username mirror_example --password password --vhost mirror_example declare queue name=mirror-exactly.messages durable=true

Declare mirror-nodes.messages queue.

$ ./rabbitmqadmin --username mirror_example --password password --vhost mirror_example declare queue name=mirror-nodes.messages durable=true

Declare bindings.

$ ./rabbitmqadmin --username mirror_example --password password --vhost mirror_example declare binding source=messages destination=mirror-all.messages
$ ./rabbitmqadmin --username mirror_example --password password --vhost cluster_example declare binding source=messages destination=mirror-exactly.messages
$ ./rabbitmqadmin --username mirror_example --password password --vhost cluster_example declare binding source=messages destination=mirror-nodes.messages

Publish sample message.

$ ./rabbitmqadmin --username mirror_example --password password --vhost mirror_example publish exchange=messages routing_key= payload="sample message a"

Inspect queues, notice that each queue is created on a single node.

$ ./rabbitmqadmin --username mirror_example  --password password --vhost mirror_example list queues vhost name node slave_nodes effective_policy_definition.ha-mode effective_policy_definition.ha-params  messages durable
+----------------+--------------------------+----------------+---------------------------------------+-------------------------------------+---------------------------------------+----------+---------+
|     vhost      |           name           |      node      |              slave_nodes              | effective_policy_definition.ha-mode | effective_policy_definition.ha-params | messages | durable |
+----------------+--------------------------+----------------+---------------------------------------+-------------------------------------+---------------------------------------+----------+---------+
| mirror_example | mirror-all.messages      | rabbit@rabbit  | ["rabbit@raccoon", "rabbit@reindeer"] | all                                 |                                       | 1        | True    |
| mirror_example | mirror-exactly.messages  | rabbit@rabbit  | ["rabbit@reindeer"]                   | exactly                             | 2                                     | 1        | True    |
| mirror_example | mirror-nodes.messages    | rabbit@raccoon | ["rabbit@reindeer"]                   | nodes                               | ["rabbit@reindeer", "rabbit@raccoon"] | 1        | True    |
+----------------+--------------------------+----------------+---------------------------------------+-------------------------------------+---------------------------------------+----------+---------+

Stop the RabbitMQ node on which the above-mentioned queues reside.

$ sudo systemctl stop rabbitmq-server

Inspect queues.

$ ./rabbitmqadmin --username mirror_example  --password password --vhost mirror_example list queues vhost name node slave_nodes effective_policy_definition.ha-mode effective_policy_definition.ha-params  messages durable
+----------------+--------------------------+-----------------+---------------------+-------------------------------------+---------------------------------------+----------+---------+
|     vhost      |           name           |      node       |     slave_nodes     | effective_policy_definition.ha-mode | effective_policy_definition.ha-params | messages | durable |
+----------------+--------------------------+-----------------+---------------------+-------------------------------------+---------------------------------------+----------+---------+
| mirror_example | mirror-all.messages      | rabbit@raccoon  | ["rabbit@reindeer"] | all                                 |                                       | 1        | True    |
| mirror_example | mirror-exactly.messages  | rabbit@reindeer | ["rabbit@raccoon"]  | exactly                             | 2                                     | 1        | True    |
| mirror_example | mirror-nodes.messages    | rabbit@raccoon  | ["rabbit@reindeer"] | nodes                               | ["rabbit@reindeer", "rabbit@raccoon"] | 1        | True    |
+----------------+--------------------------+-----------------+---------------------+-------------------------------------+---------------------------------------+----------+---------+

Start the stopped RabbitMQ node.

$ sudo systemctl start rabbitmq-server

Inspect queues.

$ ./rabbitmqadmin --username mirror_example  --password password --vhost mirror_example list queues vhost name node slave_nodes effective_policy_definition.ha-mode effective_policy_definition.ha-params  messages durable
+----------------+--------------------------+-----------------+--------------------------------------+-------------------------------------+---------------------------------------+----------+---------+
|     vhost      |           name           |      node       |             slave_nodes              | effective_policy_definition.ha-mode | effective_policy_definition.ha-params | messages | durable |
+----------------+--------------------------+-----------------+--------------------------------------+-------------------------------------+---------------------------------------+----------+---------+
| mirror_example | mirror-all.messages      | rabbit@raccoon  | ["rabbit@reindeer", "rabbit@rabbit"] | all                                 |                                       | 1        | True    |
| mirror_example | mirror-exactly.messages  | rabbit@reindeer | ["rabbit@raccoon"]                   | exactly                             | 2                                     | 1        | True    |
| mirror_example | mirror-nodes.messages    | rabbit@raccoon  | ["rabbit@reindeer"]                  | nodes                               | ["rabbit@reindeer", "rabbit@raccoon"] | 1        | True    |
+----------------+--------------------------+-----------------+--------------------------------------+-------------------------------------+---------------------------------------+----------+---------+

Install jq utility.

$ sudo apt install jq

Export configuration.

$ ./rabbitmqadmin --username admin --password password export config.json
$ cat config.json | jq .
{
  "rabbit_version": "3.8.0",
  "users": [
    {
      "name": "admin",
      "password_hash": "m4Gwgzra8yauPPLYAIKlAAE08uCs2sPWQsY/ncND0GKwLVgT",
      "hashing_algorithm": "rabbit_password_hashing_sha256",
      "tags": "administrator"
    },
    {
      "name": "mirror_example",
      "password_hash": "/z+hiB2k4CtaYBKYvt2nqQwoBImCU75pMIw4cBkX6Tsr5ZDp",
      "hashing_algorithm": "rabbit_password_hashing_sha256",
      "tags": "administrator"
    }
  ],
  "vhosts": [
    {
      "name": "/"
    },
    {
      "name": "mirror_example"
    }
  ],
  "permissions": [
    {
      "user": "admin",
      "vhost": "/",
      "configure": ".*",
      "write": ".*",
      "read": ".*"
    },
    {
      "user": "mirror_example",
      "vhost": "mirror_example",
      "configure": ".*",
      "write": ".*",
      "read": ".*"
    },
    {
      "user": "admin",
      "vhost": "mirror_example",
      "configure": ".*",
      "write": ".*",
      "read": ".*"
    }
  ],
  "topic_permissions": [],
  "parameters": [],
  "global_parameters": [
    {
      "name": "cluster_name",
      "value": "rabbit@rabbit"
    }
  ],
  "policies": [
    {
      "vhost": "mirror_example",
      "name": "mirror-all",
      "pattern": "^mirror-all.*",
      "apply-to": "all",
      "definition": {
        "ha-mode": "all",
        "ha-sync-mode": "automatic"
      },
      "priority": 0
    },
    {
      "vhost": "mirror_example",
      "name": "mirror-exactly",
      "pattern": "^mirror-exactly.*",
      "apply-to": "all",
      "definition": {
        "ha-mode": "exactly",
        "ha-params": 2,
        "ha-sync-mode": "automatic"
      },
      "priority": 0
    },
    {
      "vhost": "mirror_example",
      "name": "mirror-nodes",
      "pattern": "^mirror-nodes.*",
      "apply-to": "all",
      "definition": {
        "ha-mode": "nodes",
        "ha-params": [
          "rabbit@reindeer",
          "rabbit@raccoon"
        ],
        "ha-sync-mode": "automatic"
      },
      "priority": 0
    }
  ],
  "queues": [
    {
      "name": "mirror-exactly.messages",
      "vhost": "mirror_example",
      "durable": true,
      "auto_delete": false,
      "arguments": {}
    },
    {
      "name": "mirror-all.messages",
      "vhost": "mirror_example",
      "durable": true,
      "auto_delete": false,
      "arguments": {}
    },
    {
      "name": "mirror-nodes.messages",
      "vhost": "mirror_example",
      "durable": true,
      "auto_delete": false,
      "arguments": {}
    }
  ],
  "exchanges": [
    {
      "name": "messages",
      "vhost": "mirror_example",
      "type": "fanout",
      "durable": true,
      "auto_delete": false,
      "internal": false,
      "arguments": {}
    }
  ],
  "bindings": [
    {
      "source": "messages",
      "vhost": "mirror_example",
      "destination": "mirror-all.messages",
      "destination_type": "queue",
      "routing_key": "",
      "arguments": {}
    },
    {
      "source": "messages",
      "vhost": "mirror_example",
      "destination": "mirror-exactly.messages",
      "destination_type": "queue",
      "routing_key": "",
      "arguments": {}
    },
    {
      "source": "messages",
      "vhost": "mirror_example",
      "destination": "mirror-nodes.messages",
      "destination_type": "queue",
      "routing_key": "",
      "arguments": {}
    }
  ]
}

Additional notes

Clustering Guide

Highly Available (Mirrored) Queues