DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Intro to Spring Data MongoDB Reactive and How to Move It to the Cloud
  • Spring Boot With Kubernetes
  • 7 Microservices Best Practices for Developers
  • How Kafka Can Make Microservice Planet a Better Place

Trending

  • Mastering Advanced Aggregations in Spark SQL
  • Is Agile Right for Every Project? When To Use It and When To Avoid It
  • Developers Beware: Slopsquatting and Vibe Coding Can Increase Risk of AI-Powered Attacks
  • Memory Leak Due to Time-Taking finalize() Method
  1. DZone
  2. Software Design and Architecture
  3. Containers
  4. Using RabbitMQ in Cluster

Using RabbitMQ in Cluster

Clustering and high availability configuration with RabbitMQ are pretty simple. Its UI management console offers good s support in the cluster monitoring process.

By 
Piotr Mińkowski user avatar
Piotr Mińkowski
·
Updated Mar. 16, 17 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
38.4K Views

Join the DZone community and get the full member experience.

Join For Free

RabbitMQ has grown into the most popular message broker software, which we can see in the picture from Google Trends below. Although it is written in the not-very-popular Erlang language, implements rather complex Advanced Message Queueing Protocol (AMQP) and is not as fast as some of the competing software like Apache Kafka or ZeroMQ its position is second to none. But why?

Image title

The answer is that RabbitMQ is a leader in reliability. It has a great support for clustering, high availibility, and failover. All its features are well-documented and it is easy to use and configure — even if we are talking about such mechanisms as clustering or high availability.

In this post, I’m going to show you how to run some instances of RabbitMQ provided in Docker containers in the cluster with highly available (HA) queues. Based on the sample Java application, we’ll see how to send and receive messages from the RabbitMQ cluster and check how this message broker handles a large number of incoming messages.

A sample Spring Boot application is available on GitHub. Here is a picture illustrating the architecture of the presented solution.

Image title

We use the Docker official repository of RabbitMQ. Here are commands for running three RabbitMQ nodes. The first node is the master of the cluster and the two other nodes will join him. We use container management to enable an UI administration console for each node. Every node has default connection and UI management ports exposed. The important thing is to link the rabbit2 and rabbit3containers to the rabbit1container, as well as rabbit3 to rabbit2. It is necessary while joining to cluster mastering by rabbit1.

docker run -d --hostname rabbit1 --name rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitcluster' -p 30000:5672 -p 30001:15672 rabbitmq:management
docker run -d --hostname rabbit2 --name rabbit2 --link rabbit1:rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitcluster' -p 30002:5672 -p 30003:15672 rabbitmq:management
docker run -d --hostname rabbit3 --name rabbit3 --link rabbit1:rabbit1 --link rabbit2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitcluster' -p 30004:5672 -p 30005:15672 rabbitmq:management

Now, there are three RabbitMQ running instances. We can go to the UI management console for all of those instances available as docker containers — for example, http://192.168.99.100:30001 (rabbit1). Each instance is available on its independent cluster, like we see in the pictures below. We would like to make all instances working in same cluster, rabbit@rabbit1.

rabbit_cluster

rabbit_cluster2

Here, the set of commands runs on the rabbit2 instance for joining cluster rabbit@rabbit1. The same set should be run on the rabbit3 node. In the beginning, we have to connect to the Docker container and run a Bash command. Before running the RabbitMQ join_cluster command, we have to stop the broker.

docker exec -i -t rabbit2 \bash
root@rabbit2:/# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...
root@rabbit2:/# rabbitmqctl join_cluster rabbit@rabbit1
Clustering node rabbit@rabbit2 with rabbit@rabbit1 ...
root@rabbit2:/# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...

If everything was successful, we should see cluster name rabbit@rabbit1 in the upper-right corner of the rabbit2 management console. You should also see a list of running nodes in the Nodes section. You can also check cluster status by running on every node command rabbitmqctl cluster_status, which should also display a list of all cluster nodes.

Image title

After starting, all nodes go to the UI management console on one of the nodes. Now, we are going to configure high availability for selected queue. It is not important which node you choose because they are in one cluster. In the Queues tab, create a queue with name q.example. Then, go to the Admin tab, select the Policies section, and create a new policy.

In the picture below, you can see policy I have created. I selected ha-mode=all, which means that is mirrored across all nodes in the cluster and when a new node is added to the cluster, the queue will be mirrored to that node. There are also nodes modes, another aspect of RabbitMQ high availability. In the pattern field, enter your queue name and select Queues. If everything was successful, you should see the ha-all feature in the queue row.

Image title

One of the greatest advantages of RabbitMQ is monitoring. You can see many statistics like memory, disk usage, I/O statistics, detailed message rates, graphs, etc. In the pictures below, you can see a comparision of persistence statistics for a single instance of RabbitMQ (on the top) and three clustered instances (on the bottom).

Image titleImage title

In the next pictures, we have a comparision of I/O statistics also for a single instance (top) and three clustered instances (bottom).

Image title

Image title

And finally, there are pictures with the visualization of process statistics between a single and three clustered instances. Here, you can see statistics like memory and disk usage. 

Image title

Image title

Generally, there are no big differences in the statistics between single standalone instance and three clustered instances. For testing, I used a sample application written Java and Spring that sends 100k messages to the direct exchange and the second application, which listens for incoming messages to the target queue.

The first peak in each graph presents filling the queue with messages sent by the client and the second peak represent them receiving theirs from the queue by the client listener — although there is no big difference in statistics on RabbitMQ server, we could observe them in the client and listener sample application.

Sending 100k messages to the single instance took about 10 seconds, while sending them to the first instance from cluster took about 54 seconds. There is also a huge difference in processing messages on the receiver side. Receiving messages from single standalone queue took about 43 seconds while receiving then from the clustered HA queue took about 132 seconds.

RabbitMQ has a great support in Spring framework. There many projects that use RabbitMQ implementation by default — for example, Spring Cloud Stream, Spring Cloud Sleuth. I’m going to show you a sample Spring Boot application that sends messages to the RabbitMQ cluster and receives them from the HA queue.

Here’s the main class of application. We enable RabbitMQ listener by declaring @EnableRabbit on the class and @RabbitListener on the receiving method. We also have to declare the listened queue, broker connection factory, and listener container factory to allow listener concurrency.

Inside CachingConnectionFactory, we set all three addresses of RabbitMQ cluster instances: 192.168.99.100:30000, 192.168.99.100:30002, 192.168.99.100:30004. In the receiving method, we are only logging incoming message to console and counting time from application startup.

@SpringBootApplication
@EnableRabbit
public class Listener {

  private static Logger logger = Logger.getLogger("Listener");

  private Long timestamp;

  public static void main(String[] args) {
    SpringApplication.run(Listener.class, args);
  }

  @RabbitListener(queues = "q.example")
  public void onMessage(Order order) {
    if (timestamp == null)
      timestamp = System.currentTimeMillis();
    logger.info((System.currentTimeMillis() - timestamp) + " : " + order.toString());
  }

  @Bean
  public ConnectionFactory connectionFactory() {
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAddresses("192.168.99.100:30000,192.168.99.100:30002,192.168.99.100:30004");
    connectionFactory.setChannelCacheSize(10);
    return connectionFactory;
  }

  @Bean
  public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory());
    factory.setConcurrentConsumers(10);
    factory.setMaxConcurrentConsumers(20);
    return factory;
  }

  @Bean
  public Queue queue() {
    return new Queue("q.example");
  }

}

Here's sender main class:

@SpringBootApplication
public class Sender {

  private static Logger logger = Logger.getLogger("Sender");

  @Autowired
  RabbitTemplate template;

  public static void main(String[] args) {
    SpringApplication.run(Sender.class, args);
  }

  @PostConstruct
  public void send() {
    for (int i = 0; i < 100000; i++) {
      int id = new Random().nextInt(100000);
      template.convertAndSend(new Order(id, "TEST"+id, OrderType.values()[(id%2)]));
    }
    logger.info("Sending completed.");
  }

  @Bean
  public ConnectionFactory connectionFactory() {
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAddresses("192.168.99.100:30000,192.168.99.100:30002,,192.168.99.100:30004");
    return connectionFactory;
  }

  @Bean
  public RabbitTemplate template() {
    RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
    rabbitTemplate.setExchange("ex.example");
    return rabbitTemplate;
  }

}

Conclusion

Clustering and high availability configuration with RabbitMQ are pretty simple. I like Rabbit MQ for its support in the cluster monitoring process with UI management console. In my opinion, it is user-friendly and intuitive. Sending and receiving messages from an HA-clustered queue is much slower than for a single standalone instance, but is still acceptable.

Docker (software) clustering Spring Framework

Published at DZone with permission of Piotr Mińkowski, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Intro to Spring Data MongoDB Reactive and How to Move It to the Cloud
  • Spring Boot With Kubernetes
  • 7 Microservices Best Practices for Developers
  • How Kafka Can Make Microservice Planet a Better Place

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: