{"id":328,"date":"2019-08-15T08:29:12","date_gmt":"2019-08-15T12:29:12","guid":{"rendered":"http:\/\/bhoey.com\/blog\/?p=328"},"modified":"2020-06-23T12:24:12","modified_gmt":"2020-06-23T16:24:12","slug":"high-availability-rabbitmq-with-mirrored-queues","status":"publish","type":"post","link":"https:\/\/bhoey.com\/blog\/high-availability-rabbitmq-with-mirrored-queues\/","title":{"rendered":"High Availability RabbitMQ With Mirrored Queues"},"content":{"rendered":"<h3>Background<\/h3>\n<p>RabbitMQ is a robust message queue which features high message throughput, configurable acknowledgements, an intuitive management GUI and wide client library support. Written in Erlang, RabbitMQ has built a reputation for outstanding stability which makes it a popular choice as a core infrastructure system.<\/p>\n<p>As you plan your overall messaging architecture a universal requirement is to minimize downtime from any single point of failure. Fortunately RabbitMQ comes equipped with built-in high-availability facilities, your tolerance for message loss will determine the which of the available HA options and approaches fits best. This post will mainly focus on setting up RabbitMQ mirrored queues which provide the highest protection against message loss.<\/p>\n<h3>Clustering vs Mirrored Queues<\/h3>\n<p>For the purpose of this post, its sufficient to know that RabbitMQ clusters do in fact replicate items like users, exchanges, routing keys and queues among member nodes, but importantly they do not replicate the messages themselves<sup><a href=\"#what_replicated\">1<\/a><\/sup>. In the event of a RabbitMQ node failure, clients can reconnect to a different node, declare their queues and begin to receive published messages from that time on, however any messages that were still waiting in a queue located on the failed node will be lost if the host becomes unrecoverable.<\/p>\n<p>Mirrored queues introduce an additional level of protection by replicating published messages to other nodes in the cluster as well. In the event of a node failure, another cluster node will assume the queue master role for mirrored queues that were present on the failed node and then proceed to handle messaging operations for these mirrored queues thereafter, including serving messages that were still queued up at the time of the failure. This additional protection however does come at a cost of reduced message throughput and increased server load.<\/p>\n<h3>Requirements<\/h3>\n<p>Before we can configure mirrored queues we need to first have a RabbitMQ cluster in place.<\/p>\n<div style=\"padding-left: 25px;\">\n<h4>RabbitMQ Cluster Requirements<\/h4>\n<ol>\n<li>Two or more RabbitMQ nodes<\/li>\n<li>Identical Erlang cookie value in each node<\/li>\n<li>Peer discovery method<\/li>\n<\/ol>\n<\/div>\n<p>The <b>identical Erlang cookie value<\/b> is necessary for the nodes to authenticate between themselves to form a cluster. Since we will be using docker-compose for this demo we can specify this value as an environment variable and the default RabbitMQ docker-entrypoint.sh script will write this value to the correct file. If you are deploying RabbitMQ to hosts directly or using some other configuration orchestration see the official clustering guide for the location of the cookie file<sup><a href=\"#cluster_guide\">2<\/a><\/sup>.<\/p>\n<p>The <b>peer discovery method<\/b> we will use is a hard-coded list of nodes that make up the cluster. This is the simplest method which avoids introducing additional dependencies, making it perfect for short demonstration purposes, but you'll likely want to select a more dynamic peer discovery method outlined in the cluster formation documentation<sup><a href=\"#peer_disc\">3<\/a><\/sup>.<\/p>\n<div style=\"padding-left: 25px;\">\n<h4>Mirrored Queues Requirements<\/h4>\n<ol>\n<li>RabbitMQ Cluster<\/li>\n<li>High-availability policy<\/li>\n<li>One or more queues to apply the HA policy to<\/li>\n<\/ol>\n<\/div>\n<p>As mentioned above, mirrored queue functionality is layered on top of the <b>cluster<\/b> mechanisms, so you'll need to set up a cluster if you want to enable mirrored queues.<\/p>\n<p>The <b>high-availability policy<\/b> defines the characteristics of the message replication, such as replication batch size, along with a pattern to match against queues you want mirrored. In the demo below we will indicate that the policy should apply to any queues with names starting with 'ha.'.<\/p>\n<h3>Demo<\/h3>\n<h4>Demo Overview<\/h4>\n<p>For this demo we will spin up two RabbitMQ nodes from scratch in a cluster configuration using docker-compose. We will also leverage the management plugin to pre-define an HA policy, a single queue to be mirrored and other initial configurations so that our cluster has everything it needs to be fully functional from the start.<\/p>\n<p>An important thing to note is that the data volume mapping has been commented out in the docker-compose.yml file. This was done since this demo is meant to highlight how to start fresh without any previous state information. When the cluster is running, state information will be persisted to the data volume and will be read in on subsequent starts. <b>Since this demo does not map the data volume, any state information will be lost when the node is shut down<\/b>. In real world use you'll want to map the data volume to an appropriate location on your system to avoid losing data on restart.<\/p>\n<h4>Demo Files<\/h4>\n<p>Below are the files necessary to start up two RabbitMQ nodes using docker-compose. They are intentionally minimalist to highlight the required elements and provide a stable base to allow for experimentation.<\/p>\n<h5>rabbitmq.conf<\/h5>\n<p>The new style rabbitmq.conf file below simply defines the peer discovery method, the nodes participating in the cluster and indicates the definitions file to load on start (this last functionality is provided by the management plugin).<\/p>\n<div>\n<div id=\"highlighter_950753\" class=\"syntaxhighlighter nogutter  benconf\">\n<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"benconf comments\"># Load definitions file that includes HA policy<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"benconf variable\">management.load_definitions =<\/code> <code class=\"benconf plain\">\/etc\/rabbitmq\/definitions.json<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"benconf comments\"># Declare cluster via host list<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"benconf variable\">cluster_formation.peer_discovery_backend =<\/code> <code class=\"benconf plain\">rabbit_peer_discovery_classic_config<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"benconf variable\">cluster_formation.classic_config.nodes.1 =<\/code> <code class=\"benconf plain\">rabbit@rabbit1<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"benconf variable\">cluster_formation.classic_config.nodes.2 =<\/code> <code class=\"benconf plain\">rabbit@rabbit2<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h5>rabbit1-definitions.json<\/h5>\n<p>The primary reason we need to use a definition file is to pre-define the HA policy that will apply to queues created in the cluster. An interesting surprise of using a definitions file however is that by using one on a fresh RabbitMQ instance, it will skip the automatic creation of the default 'guest' user. It is therefore necessary to additionally define one or more users explicitly in the definitions file.<\/p>\n<div>\n<div id=\"highlighter_21894\" class=\"syntaxhighlighter nogutter  benjson\">\n<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"vhosts\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"name\":<\/code> <code class=\"benjson plain\">\"\/\"<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">],<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"users\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number10 index9 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"name\":<\/code> <code class=\"benjson plain\">\"admin\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number11 index10 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"password\":<\/code> <code class=\"benjson plain\">\"admin\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"tags\":<\/code> <code class=\"benjson plain\">\"administrator\"<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">],<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><\/div>\n<div class=\"line number16 index15 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"permissions\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number17 index16 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"user\":<\/code><code class=\"benjson plain\">\"admin\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number19 index18 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"vhost\":<\/code><code class=\"benjson plain\">\"\/\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"configure\":<\/code><code class=\"benjson plain\">\".*\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number21 index20 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"write\":<\/code><code class=\"benjson plain\">\".*\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number22 index21 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"read\":<\/code><code class=\"benjson plain\">\".*\"<\/code><\/div>\n<div class=\"line number23 index22 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number24 index23 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">],<\/code><\/div>\n<div class=\"line number25 index24 alt2\"><\/div>\n<div class=\"line number26 index25 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"policies\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number27 index26 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number28 index27 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"name\":<\/code> <code class=\"benjson plain\">\"ha-all\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number29 index28 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"apply-to\":<\/code> <code class=\"benjson plain\">\"all\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number30 index29 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"definition\":<\/code> <code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number31 index30 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"ha-mode\":<\/code> <code class=\"benjson plain\">\"all\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number32 index31 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"ha-sync-mode\":<\/code> <code class=\"benjson plain\">\"automatic\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number33 index32 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"ha-sync-batch-size\":<\/code> <code class=\"benjson plain\">1<\/code><\/div>\n<div class=\"line number34 index33 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">},<\/code><\/div>\n<div class=\"line number35 index34 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"pattern\":<\/code> <code class=\"benjson plain\">\"^ha\\.\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number36 index35 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"priority\":<\/code> <code class=\"benjson plain\">0,<\/code><\/div>\n<div class=\"line number37 index36 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"vhost\":<\/code> <code class=\"benjson plain\">\"\/\"<\/code><\/div>\n<div class=\"line number38 index37 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number39 index38 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">],<\/code><\/div>\n<div class=\"line number40 index39 alt1\"><\/div>\n<div class=\"line number41 index40 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"queues\":<\/code><\/div>\n<div class=\"line number42 index41 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number43 index42 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number44 index43 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"name\":<\/code> <code class=\"benjson plain\">\"ha.queue1\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number45 index44 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"vhost\":<\/code> <code class=\"benjson plain\">\"\/\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number46 index45 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"durable\":<\/code> <code class=\"benjson plain\">true,<\/code><\/div>\n<div class=\"line number47 index46 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"auto_delete\":<\/code> <code class=\"benjson plain\">false,<\/code><\/div>\n<div class=\"line number48 index47 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"arguments\":<\/code> <code class=\"benjson plain\">{}<\/code><\/div>\n<div class=\"line number49 index48 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number50 index49 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">]<\/code><\/div>\n<div class=\"line number51 index50 alt2\"><code class=\"benjson plain\">}<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h5>rabbit2-definitions.json<\/h5>\n<p>The rabbit2 definitions file can in fact just be an empty file as it will sync the configurations from the rabbit1 node when joining the cluster. However to err on the side of caution I prefer to include a user and permissions as well as the HA policy definition in this file in case the cluster gets in some kind of split-brain state that would need manual intervention.<\/p>\n<p>It should be noted what <b><u>is not<\/u><\/b> defined in the rabbit2 file is the 'ha.queue1' definition since whichever node a queue is declared on becomes that queue's master node.<\/p>\n<div>\n<div id=\"highlighter_147479\" class=\"syntaxhighlighter nogutter  benjson\">\n<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"vhosts\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"name\":<\/code> <code class=\"benjson plain\">\"\/\"<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">],<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"users\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number10 index9 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"name\":<\/code> <code class=\"benjson plain\">\"admin\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number11 index10 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"password\":<\/code> <code class=\"benjson plain\">\"admin\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"tags\":<\/code> <code class=\"benjson plain\">\"administrator\"<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">],<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><\/div>\n<div class=\"line number16 index15 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"permissions\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number17 index16 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"user\":<\/code><code class=\"benjson plain\">\"admin\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number19 index18 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"vhost\":<\/code><code class=\"benjson plain\">\"\/\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"configure\":<\/code><code class=\"benjson plain\">\".*\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number21 index20 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"write\":<\/code><code class=\"benjson plain\">\".*\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number22 index21 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"read\":<\/code><code class=\"benjson plain\">\".*\"<\/code><\/div>\n<div class=\"line number23 index22 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number24 index23 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">],<\/code><\/div>\n<div class=\"line number25 index24 alt2\"><\/div>\n<div class=\"line number26 index25 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"policies\":<\/code> <code class=\"benjson plain\">[<\/code><\/div>\n<div class=\"line number27 index26 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number28 index27 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"name\":<\/code> <code class=\"benjson plain\">\"ha-all\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number29 index28 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"apply-to\":<\/code> <code class=\"benjson plain\">\"all\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number30 index29 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"definition\":<\/code> <code class=\"benjson plain\">{<\/code><\/div>\n<div class=\"line number31 index30 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"ha-mode\":<\/code> <code class=\"benjson plain\">\"all\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number32 index31 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"ha-sync-mode\":<\/code> <code class=\"benjson plain\">\"automatic\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number33 index32 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"ha-sync-batch-size\":<\/code> <code class=\"benjson plain\">1<\/code><\/div>\n<div class=\"line number34 index33 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">},<\/code><\/div>\n<div class=\"line number35 index34 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"pattern\":<\/code> <code class=\"benjson plain\">\"^ha\\.\"<\/code><code class=\"benjson plain\">,<\/code><\/div>\n<div class=\"line number36 index35 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"priority\":<\/code> <code class=\"benjson plain\">0,<\/code><\/div>\n<div class=\"line number37 index36 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson string bold\">\"vhost\":<\/code> <code class=\"benjson plain\">\"\/\"<\/code><\/div>\n<div class=\"line number38 index37 alt1\"><code class=\"benjson spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"benjson plain\">}<\/code><\/div>\n<div class=\"line number39 index38 alt2\"><code class=\"benjson spaces\">&nbsp;&nbsp;<\/code><code class=\"benjson plain\">]<\/code><\/div>\n<div class=\"line number40 index39 alt1\"><code class=\"benjson plain\">}<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h5>docker-compose.yml<\/h5>\n<p>The docker-compose.yml file brings everything together under one umbrella. It defines both RabbitMQ instances, the files and ports to map, and the shared Erlang cookie value.<\/p>\n<p>One thing to note is that I've customized rabbit2's 'command' value in order to stagger the startup of the two nodes to avoid a race condition where neither node believes its the primary<sup><a href=\"#race\">4<\/a><\/sup>.<\/p>\n<div>\n<div id=\"highlighter_884619\" class=\"syntaxhighlighter nogutter  yaml\">\n<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"yaml variable\">version:<\/code> <code class=\"yaml string\">\"2\"<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"yaml variable\">services:<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">rabbit1:<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">image:<\/code> <code class=\"yaml plain\">rabbitmq<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">3-management<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">container_name:<\/code> <code class=\"yaml plain\">rabbit1<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">hostname:<\/code> <code class=\"yaml plain\">rabbit1<\/code><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">ports:<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">5672<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">5672<\/code><\/div>\n<div class=\"line number10 index9 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">15672<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">15672<\/code><\/div>\n<div class=\"line number11 index10 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">environment:<\/code><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">RABBITMQ_ERLANG_COOKIE=shared_cookie<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">volumes:<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">$PWD\/rabbit1-definitions.json<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">\/etc\/rabbitmq\/definitions.json<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">ro<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">$PWD\/rabbitmq.conf<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">\/etc\/rabbitmq\/rabbitmq.conf<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">ro<\/code><\/div>\n<div class=\"line number16 index15 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml comments\"># - $PWD\/rabbit1-data:\/var\/lib\/rabbitmq<\/code><\/div>\n<div class=\"line number17 index16 alt2\"><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">rabbit2:<\/code><\/div>\n<div class=\"line number19 index18 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">image:<\/code> <code class=\"yaml plain\">rabbitmq<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">3-management<\/code><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">container_name:<\/code> <code class=\"yaml plain\">rabbit2<\/code><\/div>\n<div class=\"line number21 index20 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">hostname:<\/code> <code class=\"yaml plain\">rabbit2<\/code><\/div>\n<div class=\"line number22 index21 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">ports:<\/code><\/div>\n<div class=\"line number23 index22 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">5673<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">5672<\/code><\/div>\n<div class=\"line number24 index23 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">15673<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">15672<\/code><\/div>\n<div class=\"line number25 index24 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">environment:<\/code><\/div>\n<div class=\"line number26 index25 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">RABBITMQ_ERLANG_COOKIE=shared_cookie<\/code><\/div>\n<div class=\"line number27 index26 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">volumes:<\/code><\/div>\n<div class=\"line number28 index27 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">$PWD\/rabbit2-definitions.json<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">\/etc\/rabbitmq\/definitions.json<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">ro<\/code><\/div>\n<div class=\"line number29 index28 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml string bold\">-<\/code> <code class=\"yaml plain\">$PWD\/rabbitmq.conf<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">\/etc\/rabbitmq\/rabbitmq.conf<\/code><code class=\"yaml constants\">:<\/code><code class=\"yaml plain\">ro<\/code><\/div>\n<div class=\"line number30 index29 alt1\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml comments\"># - $PWD\/rabbit2-data:\/var\/lib\/rabbitmq<\/code><\/div>\n<div class=\"line number31 index30 alt2\"><code class=\"yaml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"yaml variable\">command:<\/code> <code class=\"yaml plain\">sh -c <\/code><code class=\"yaml string\">'sleep 10 &amp;&amp; rabbitmq-server'<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h4>Running The Demo<\/h4>\n<p>Once the files are in place (and assuming you have docker-compose installed), its just a matter of running 'docker-compose up':<\/p>\n<div>\n<div id=\"highlighter_945520\" class=\"syntaxhighlighter nogutter  benrabbit\">\n<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"benrabbit plain\">$ docker-compose up<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"benrabbit plain\">Starting <\/code><code class=\"benrabbit variable\">rabbit1<\/code> <code class=\"benrabbit plain\">... done<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"benrabbit plain\">Starting <\/code><code class=\"benrabbit string\">rabbit2<\/code> <code class=\"benrabbit plain\">... done<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"benrabbit plain\">Attaching to <\/code><code class=\"benrabbit variable\">rabbit1<\/code><code class=\"benrabbit plain\">, <\/code><code class=\"benrabbit string\">rabbit2<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"benrabbit plain\">...<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"benrabbit variable\">rabbit1&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:39.320 [info] &lt;0.271.0&gt; <\/code><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"benrabbit variable\">rabbit1&nbsp;&nbsp;&nbsp; |&nbsp; Starting RabbitMQ 3.7.16 on Erlang 22.0.7<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"benrabbit plain\">...<\/code><\/div>\n<div class=\"line number10 index9 alt1\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.050 [info] &lt;0.296.0&gt; <\/code><\/div>\n<div class=\"line number11 index10 alt2\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; |&nbsp; Starting RabbitMQ 3.7.16 on Erlang 22.0.7<\/code><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"benrabbit plain\">...<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.476 [info] &lt;0.447.0&gt; Mirrored queue 'ha.queue1' in vhost '\/': Adding mirror on node rabbit@rabbit1: &lt;8837.647.0&gt;<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.485 [info] &lt;0.447.0&gt; Mirrored queue 'ha.queue1' in vhost '\/': Synchronising: 0 messages to synchronise<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.485 [info] &lt;0.447.0&gt; Mirrored queue 'ha.queue1' in vhost '\/': Synchronising: batch size: 4096<\/code><\/div>\n<div class=\"line number16 index15 alt1\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.486 [info] &lt;0.296.0&gt; Running boot step load_definitions defined by app rabbitmq_management<\/code><\/div>\n<div class=\"line number17 index16 alt2\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.486 [info] &lt;0.466.0&gt; Mirrored queue 'ha.queue1' in vhost '\/': Synchronising: all slaves already synced<\/code><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.486 [info] &lt;0.296.0&gt; Applying definitions from \/etc\/rabbitmq\/definitions.json<\/code><\/div>\n<div class=\"line number19 index18 alt2\"><code class=\"benrabbit plain\">...<\/code><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"benrabbit variable\">rabbit1&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.500 [info] &lt;0.385.0&gt; rabbit on node rabbit@rabbit2 up<\/code><\/div>\n<div class=\"line number21 index20 alt2\"><code class=\"benrabbit string\">rabbit2&nbsp;&nbsp;&nbsp; | 2019-08-15 01:59:49.500 [info] &lt;0.398.0&gt; rabbit on node rabbit@rabbit1 up<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h4>Verify Setup<\/h4>\n<p>After browsing to the admin GUI at <a href=\"http:\/\/localhost:15672\">http:\/\/localhost:15672<\/a> and logging in with admin\/admin you should see the following:<\/p>\n<table style=\"border: none; border-collapse: collapse;\">\n<tbody>\n<tr style=\"border: none; border-collapse: collapse;\">\n<td style=\"border: none;\"><a href=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit1.png\"><img loading=\"lazy\" width=\"150\" height=\"150\" class=\"wp-image-424\" src=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit1-150x150.png\" alt=\"nodes shown in overview screen\"><\/a><\/td>\n<td style=\"border: none;\"><a href=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit2.png\"><img loading=\"lazy\" class=\"wp-image-425\" src=\"http:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit2.png\" alt=\"the example mirrored queue\" width=\"206\" height=\"82\" srcset=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit2.png 824w, https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit2-300x120.png 300w, https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit2-768x307.png 768w\" sizes=\"(max-width: 206px) 100vw, 206px\" \/><\/a><\/td>\n<td style=\"border: none;\"><a href=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit3.png\"><img loading=\"lazy\" class=\"wp-image-426\" src=\"http:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit3.png\" alt=\"mirrored queue details\" width=\"168\" height=\"159\" srcset=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit3.png 672w, https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/08\/rabbit3-300x283.png 300w\" sizes=\"(max-width: 168px) 100vw, 168px\" \/><\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4>Client code<\/h4>\n<p>The client code setup is slightly different for connecting to mirrored queues, you'll want to indicate to the RabbitMQ\/AMQP library that there are multiple cluster nodes so that in the event of a failure they can attempt to connect to another node.<\/p>\n<p>The shuffling of the node list in both code snippets is to distribute clients across nodes. Keep in mind that the node where the queue was defined (ie the queue master) will still handle all messages routing for that queue.<\/p>\n<h5>Python<\/h5>\n<pre class=\"brush: python; notranslate\">#!\/usr\/bin\/env python3\nimport pika\nimport random\n\ncreds = pika.PlainCredentials('admin', 'admin')\nparams = [\n           pika.ConnectionParameters(host='localhost', port=5672, credentials=creds),\n           pika.ConnectionParameters(host='localhost', port=5673, credentials=creds),\n         ]\n\nrandom.shuffle(params)\n\nconnection = pika.BlockingConnection(params)\nchannel = connection.channel()\n\n# Publish message\nchannel.basic_publish(\n                       exchange='',\n                       routing_key='ha.queue1',\n                       body='Test message'\n                     )\n\n# Receive message\nresp_get_ok, resp_props, resp_body = channel.basic_get(queue='ha.queue1', auto_ack=True)\nprint(resp_body)\n\nchannel.close()\nconnection.close()\n<\/pre>\n<h5>Java<\/h5>\n<pre class=\"brush: java; notranslate\">import com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Address;\nimport com.rabbitmq.client.AMQP.BasicProperties;\nimport com.rabbitmq.client.GetResponse;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Collections;\n\npublic class RabbitMQTest{\n\n    public static void main(String[] argv) throws Exception {\n\n        List&lt;Address&gt; nodes = Arrays.asList(\n                                 new Address(\"localhost\", 5672),\n                                 new Address(\"localhost\", 5673)\n                              );\n\n        Collections.shuffle(nodes);\n\n        ConnectionFactory factory = new ConnectionFactory();\n        factory.setUsername(\"admin\");\n        factory.setPassword(\"admin\");\n\n        Connection connection = factory.newConnection(nodes);\n        Channel channel = connection.createChannel();\n\n        \/\/ Publish message\n        String exch = \"\";\n        BasicProperties props = null;\n        String routing_key = \"ha.queue1\";\n        String msg = \"Test message\";\n        channel.basicPublish(exch, routing_key, props, msg.getBytes());\n\n        \/\/ Receive message\n        String queue = \"ha.queue1\";\n        boolean autoAck = true;\n        GetResponse response = channel.basicGet(queue, autoAck);\n        byte[] body = response.getBody();\n        System.out.println(new String(body));\n\n        channel.close();\n        connection.close();\n    }\n}\n<\/pre>\n<h3>References<\/h3>\n<ol>\n<li><a id=\"what_replicated\"><\/a>What is Replicated?: <a href=\"https:\/\/www.rabbitmq.com\/clustering.html#overview-what-is-replicated\">https:\/\/www.rabbitmq.com\/clustering.html#overview-what-is-replicated<\/a><\/li>\n<li><a id=\"cluster_guide\"><\/a>Clustering Guide: <a href=\"https:\/\/www.rabbitmq.com\/clustering.html\">https:\/\/www.rabbitmq.com\/clustering.html<\/a><\/li>\n<li><a id=\"peer_disc\"><\/a>Cluster Formation and Peer Discovery: <a href=\"https:\/\/www.rabbitmq.com\/cluster-formation.html\">https:\/\/www.rabbitmq.com\/cluster-formation.html<\/a><\/li>\n<li><a id=\"race\"><\/a>Race Conditions During Initial Cluster Formation: <a href=\"https:\/\/www.rabbitmq.com\/cluster-formation.html#initial-formation-race-condition\">https:\/\/www.rabbitmq.com\/cluster-formation.html#initial-formation-race-condition<\/a><\/li>\n<li>Highly Available (Mirrored) Queues: <a href=\"https:\/\/www.rabbitmq.com\/ha.html\">https:\/\/www.rabbitmq.com\/ha.html<\/a><\/li>\n<li>Loading Definitions (Schema) at Startup<a href=\"https:\/\/www.rabbitmq.com\/management.html#load-definitions\">https:\/\/www.rabbitmq.com\/management.html#load-definitions<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>RabbitMQ is a robust message queue which features high message throughput, configurable acknowledgements, an intuitive management GUI and wide client library support. Written in Erlang, RabbitMQ has built a reputation for outstanding stability which makes it a popular choice as a core infrastructure system.<\/p>\n<p>As you plan your overall messaging architecture a universal requirement is to minimize downtime from any single point of failure. Fortunately RabbitMQ comes equipped with built-in high-availability facilities, your tolerance for message loss will determine the which of the available HA options and approaches fits best. This post will mainly focus on setting up RabbitMQ mirrored queues which provide the highest protection against message loss.&nbsp;<a href=\"https:\/\/bhoey.com\/blog\/high-availability-rabbitmq-with-mirrored-queues\/\">[Continue&nbsp;reading...] <span class=\"screen-reader-text\">High Availability RabbitMQ With Mirrored Queues<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":804,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[54],"tags":[15,57,55,56,53],"_links":{"self":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts\/328"}],"collection":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/comments?post=328"}],"version-history":[{"count":143,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts\/328\/revisions"}],"predecessor-version":[{"id":809,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts\/328\/revisions\/809"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/media\/804"}],"wp:attachment":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/media?parent=328"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/categories?post=328"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/tags?post=328"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}