Thursday, January 22, 2015

Configure ActiveMQ For High Available Using Master-Slave Paradigm With Shared File System

Introduction

Enterprise messaging with ActiveMQ is very popular nowadays. It is very matured platform and it is free! Currently, the 5.10.0 release is available at http://activemq.apache.org/activemq-5100-release.html.
In this blog, I will explain the detailed configuration about how to configure ActiveMQ instances to achieve high availability using master-slave paradigm with shared file system. The system diagram is shown below
As shown in the above diagram, I use two RedHat Linux boxes to configure 4 ActiveMQ broker nodes. All of these nodes share one file system [a directory where all nodes point to]. In general, we do not configure 2 activemq instance on one linux server in the production environment. Two or three ActiveMQ broker nodes to form a Master-Slave clustering is good enough to achieve high availability. You may create multiple clusters. I am going to explain that in later post to use Network Of Brokers with multiple clusters.
Enough topology, now let's create the nodes.

Master-Slave Configurations

We install the apache-activemq-5.10.0 at /opt/app/amq, then create 2 nodes name north and south with the following command:
cd /opt/app/amq/apache-activemq-5.10.0/bin
[amq@SANDBOXFUSEV01 bin]$ ./activemq-admin create ../../north
[amq@SANDBOXFUSEV01 bin]$ ./activemq-admin create ../../south
Now we have the following file structures

[amq@SANDBOXFUSEV01 amq]$ pwd
/opt/app/amq

[amq@SANDBOXFUSEV01 amq]$ ls -lart
total 24
drwxr-xr-x.  3 root root     4096 Jan 14 10:27 ..
lrwxrwxrwx.  1 amq  amq        23 Jan 14 10:29 activemq -> apache-activemq-5.10.0/
drwxr-xr-x. 11 amq  amq      4096 Jan 14 10:42 apache-activemq-5.10.0
drwxrwxr-x.  3 amq  amq      4096 Jan 20 12:38 tomcat
drwxrwxr-x.  4 amq  amq      4096 Jan 24 14:04 north
drwxr-xr-x.  6 amq  amqadmin 4096 Jan 24 14:06 .
drwxrwxr-x.  4 amq  amq      4096 Jan 24 14:06 south

Configure North

Now we need to modify the activemq.xml file with the following changes: ]
 17     
 
 47         
 48             
 49         
 
 58         
 59             
 60         
 
 88         
 89             
 90             
 91             
 92             
 93             
 94             
 95         
            ....
       
The line with useJmx="true" is for enable JMX and the line

is to tell ActiveMQ to use port 11099 as JMX connection port. The rmiServerPort must be defined, otherwise, the remote access will not be possible. The reason for this is that most enterprise environment block the unspecified port.

Configure South

The South instance will be similar as the North. We just need to change the port number. For the completeness, here are the changes:
 
 17     
 
 47         
 48             
 49         
 
 58         
 59             
 60         
 
 88         
 90             
 91             
 92             
 93             
 94             
 95         
            ....
       

Do the same for the second node. The start the north node on the first server by executing the following command:

Master-Slave In Action

Now, we have done all the configuration changes. We can start all the process and to see how this paradigm of high availability works.
cd /opt/app/amq/north/bin
./north start

I have created two aliases which are very useful:

alias amqjava='ps -eaf | egrep java | egrep -v grep | egrep amq'
alias amqport='netstat -anp | egrep tcp | egrep java | egrep -v grep'

Where amqjava is to check java process owned by amq user, and amqport is to check port information about amq java process. Run amqport command immediately after you start the amq java process. Here the port information you will see:

tcp        0      0 :::41882                    :::*                        LISTEN      17720/java
tcp        0      0 :::1883                     :::*                        LISTEN      17720/java
tcp        0      0 :::11099                    :::*                        LISTEN      17720/java
tcp        0      0 :::44444                    :::*                        LISTEN      17720/java
tcp        0      0 :::8161                     :::*                        LISTEN      17720/java
tcp        0      0 :::5672                     :::*                        LISTEN      17720/java
tcp        0      0 :::61613                    :::*                        LISTEN      17720/java
tcp        0      0 :::61614                    :::*                        LISTEN      17720/java
tcp        0      0 :::61616                    :::*                        LISTEN      17720/java
tcp        0      0 ::ffff:10.66.13.119:37444   ::ffff:10.66.13.119:44444   ESTABLISHED 17720/java
tcp        0      0 ::ffff:127.0.0.1:36187      ::ffff:127.0.0.1:11099      ESTABLISHED 17720/java
tcp        0      0 ::ffff:10.66.13.119:44444   ::ffff:10.66.13.119:37444   ESTABLISHED 17720/java
tcp        0      0 ::ffff:127.0.0.1:11099      ::ffff:127.0.0.1:36187      ESTABLISHED 17720/java

Another way to check these port is to use lsof command as shwon below:

[amq@SANDBOXFUSEV01 bin]$ lsof -P -iTCP
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java    17720  amq    9u  IPv6 1300784      0t0  TCP *:41882 (LISTEN)
java    17720  amq  111u  IPv6 1300785      0t0  TCP *:11099 (LISTEN)
java    17720  amq  113u  IPv6 1300786      0t0  TCP *:44444 (LISTEN)
java    17720  amq  125u  IPv6 1300795      0t0  TCP *:61616 (LISTEN)
java    17720  amq  126u  IPv6 1300796      0t0  TCP *:5672 (LISTEN)
java    17720  amq  127u  IPv6 1300797      0t0  TCP *:61613 (LISTEN)
java    17720  amq  128u  IPv6 1300798      0t0  TCP *:1883 (LISTEN)
java    17720  amq  129u  IPv6 1300800      0t0  TCP *:61614 (LISTEN)
java    17720  amq  136u  IPv6 1300811      0t0  TCP *:8161 (LISTEN)

At this time, the ActiveMQ north instance is running. I can verify this by open brower with URL of sandboxfusev01:8161. This is activemq embedded web console. The default password is admin/admin

Now lets start the second instance in the folder of /opt/app/amq/south

cd /opt/app/amq/south/bin
./south start

I can see the following stdout:

[amq@SANDBOXFUSEV01 bin]$ ./south start
INFO: Using default configuration
(you can configure options in one of these file: /etc/default/activemq /home/amq/.activemqrc)

INFO: Invoke the following command to create a configuration file
/opt/app/amq/apache-activemq-5.10.0/bin/activemq setup [ /etc/default/activemq | /home/amq/.activemqrc ]

INFO: Using java '/usr/bin/java'
INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details
INFO: pidfile created : '/opt/app/amq/south/data/activemq-SANDBOXFUSEV01.pid' (pid '17879')

When I chack amqjava, I get the following

[amq@SANDBOXFUSEV01 bin]$ amqjava
amq      17720     1  0 18:52 pts/0    00:00:08 /usr/bin/java -Xms1G -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/opt/app/amq/north/conf/login.config -Dcom.sun.management.jmxremote -Djava.awt.headless=true -Djava.io.tmpdir=/opt/app/amq/north/tmp -Dactivemq.classpath=/opt/app/amq/north/conf; -Dactivemq.home=/opt/app/amq/apache-activemq-5.10.0 -Dactivemq.base=/opt/app/amq/north -Dactivemq.conf=/opt/app/amq/north/conf -Dactivemq.data=/opt/app/amq/north/data -jar /opt/app/amq/apache-activemq-5.10.0/bin/activemq.jar start
amq      17879     1 24 19:24 pts/0    00:00:02 /usr/bin/java -Xms1G -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/opt/app/amq/south/conf/login.config -Dcom.sun.management.jmxremote -Djava.awt.headless=true -Djava.io.tmpdir=/opt/app/amq/south/tmp -Dactivemq.classpath=/opt/app/amq/south/conf; -Dactivemq.home=/opt/app/amq/apache-activemq-5.10.0 -Dactivemq.base=/opt/app/amq/south -Dactivemq.conf=/opt/app/amq/south/conf -Dactivemq.data=/opt/app/amq/south/data -jar /opt/app/amq/apache-activemq-5.10.0/bin/activemq.jar start
[amq@SANDBOXFUSEV01 bin]$

This indicating there are two activemq java process are running with process ID of 17720 and 17879. Now lets check what port has been opened by these two java processes

[amq@SANDBOXFUSEV01 bin]$ amqport
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 :::41882                    :::*                        LISTEN      17720/java
tcp        0      0 :::1883                     :::*                        LISTEN      17720/java
tcp        0      0 :::11099                    :::*                        LISTEN      17720/java
tcp        0      0 :::44444                    :::*                        LISTEN      17720/java
tcp        0      0 :::44445                    :::*                        LISTEN      17879/java
tcp        0      0 :::8161                     :::*                        LISTEN      17720/java
tcp        0      0 :::12099                    :::*                        LISTEN      17879/java
tcp        0      0 :::5672                     :::*                        LISTEN      17720/java
tcp        0      0 :::36010                    :::*                        LISTEN      17879/java
tcp        0      0 :::61613                    :::*                        LISTEN      17720/java
tcp        0      0 :::61614                    :::*                        LISTEN      17720/java
tcp        0      0 :::61616                    :::*                        LISTEN      17720/java
[amq@SANDBOXFUSEV01 bin]$

Interestingly, I see only 44445 and 12099 ports opened by the second java process. You may expect 61626 and other ports are open. This is because the south instance is in standby mode. Now if I tail the log at /opt/app/amq/south/data/activemq.log, if the following output:

[amq@SANDBOXFUSEV01 bin]$ tail -10f ../data/activemq.log
2015-01-24 19:33:21,686 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:33:31,688 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:33:41,689 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:33:51,691 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:34:01,696 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:34:11,699 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:34:21,728 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:34:31,730 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:34:41,731 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:34:51,733 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main
2015-01-24 19:35:01,736 | INFO  | Database /amqdata/master-slave/data/kahadb/lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOException: File '/amqdata/master-slave/data/kahadb/lock' could not be locked. | org.apache.activemq.store.SharedFileLocker | main

As you can see, every 10 seconds, the south instance is throwing an IOException sayiing the lock at '/amqdata/master-slave/data/kahadb/lock' is not accessable. This is exactly what we want. This means the south instance is a slave node now. For the purpose of showing you extra information, I can use lsof utility to check who is locking the file of '/amqdata/master-slave/data/kahadb/lock' by the following command:

[amq@SANDBOXFUSEV01 kahadb]$ cd /amqdata/master-slave/data/kahadb
[amq@SANDBOXFUSEV01 kahadb]$ ls
db-2.log  db.data  db.redo  lock
[amq@SANDBOXFUSEV01 kahadb]$ lsof | egrep lock | egrep java
java      17720       amq  118uw     REG               0,21        0 4321950309 /amqdata/master-slave/data/kahadb/lock
[amq@SANDBOXFUSEV01 kahadb]$ amqjava
amq      17720     1  0 18:52 pts/0    00:00:09 /usr/bin/java -Xms1G -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/opt/app/amq/north/conf/login.config -Dcom.sun.management.jmxremote -Djava.awt.headless=true -Djava.io.tmpdir=/opt/app/amq/north/tmp -Dactivemq.classpath=/opt/app/amq/north/conf; -Dactivemq.home=/opt/app/amq/apache-activemq-5.10.0 -Dactivemq.base=/opt/app/amq/north -Dactivemq.conf=/opt/app/amq/north/conf -Dactivemq.data=/opt/app/amq/north/data -jar /opt/app/amq/apache-activemq-5.10.0/bin/activemq.jar start
amq      17879     1  0 19:24 pts/0    00:00:03 /usr/bin/java -Xms1G -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/opt/app/amq/south/conf/login.config -Dcom.sun.management.jmxremote -Djava.awt.headless=true -Djava.io.tmpdir=/opt/app/amq/south/tmp -Dactivemq.classpath=/opt/app/amq/south/conf; -Dactivemq.home=/opt/app/amq/apache-activemq-5.10.0 -Dactivemq.base=/opt/app/amq/south -Dactivemq.conf=/opt/app/amq/south/conf -Dactivemq.data=/opt/app/amq/south/data -jar /opt/app/amq/apache-activemq-5.10.0/bin/activemq.jar start
[amq@SANDBOXFUSEV01 kahadb]$

From above command and result, I can see that the java process with ID of 17720 is holding the lock at /amqdata/master-slave/data/kahadb/lock.

In the same maner, we can start the two ActiveMA instance in the second server. We have proved the only one instance of activemq node in the cluster is holding the lock and function

Summary

So far we have covered the basic configuration of ActiveMQ for high availability using the Master-Slave paradigm with shared file system. In this paradigm, only master will grab the lock all the ActiveMA instances in the same cluster will be in a standby mode. We call them slaves. I also explained how to setup JMX and how to check ports which are ready for connections.

Before we further explain how Master-Slave paradigm works, I would like demonstrate how to use JVisualVM and Tomcat container to monitor ActiveMA instances (nodes). I will cover these two topics in the next two blogs.

1 comment:

  1. i was create two broker node , broker-1 and broker-2 and also change the activemq.xml file in broker-1 but i am not able to start the first node

    ReplyDelete

Anypoint Studio Error: The project is missing Munit lIbrary to run tests

Anypoint Studio 7.9 has a bug. Even if we following the article: https://help.mulesoft.com/s/article/The-project-is-missing-MUnit-libraries-...