Building Highly available ACTIVEMQ systems is very important in a production environment, and a single point of ACTIVEMQ as an enterprise application does not meet the requirements of high availability and clustering, so ACTIVEMQ provides a variety of deployment methods Master-slave, broker cluster, etc. But by analyzing a variety of deployment options, I think we need to combine the two deployment approaches to meet our company's distributed and highly available requirements, so we'll focus on how to combine the two deployment approaches later on.
Since the beginning of activemq5.9.0, ACTIVEMQ's cluster implementation has eliminated the traditional pure Master slave approach, adding ZOOKEEPER+LEVELDB-based implementations, and two other ways: directory sharing and database sharing still exist.
1, Master-slave Deployment method
1), Shared Filesystem Master-slave Way
2), Shared Database master-slave mode
3), replicated LevelDB Store mode
The first scenario also supports N AMQ instance networking, but since he is based on kahadb storage policies, it is also flexible, efficient and secure to deploy on distributed file systems.
The second scenario is similar to the shared filesystem approach, except that the shared storage media is changed from the file system to a database and supports N AMQ instance networking, but his performance is limited to the database;
The third scenario is the new feature after ActiveMQ5.9, using zookeeper to coordinate the selection of a node as master. The selected master Broker node opens and accepts client connections.
Other node into slave mode, connect master and synchronize their storage status. Slave does not accept client connections. All storage operations are copied to the slaves connected to master.
If Master is dead, the newly updated slave is allowed to become master. fialed node can rejoin the network and connect master into slave mode. All message operations for disk that need to be synchronized will wait for the storage state to be replicated to the other legal nodes before completing the operation. So, if you configure replicas=3, then the legal size is (3/2) +1=2. Master will store and update and then wait (2-1) = 1 Slave storage and update complete before reporting success. As for why is 2-1, familiar with zookeeper should know that there is a node to be as a viewer exists.
One new master is selected, you need to protect at least one legal node online to be able to find node with the latest status. This node will become the new master. Therefore, it is recommended to run at least 3 replica nodes to prevent a node from failing and the service is interrupted.
Shared Filesystem Master-slave Way
The shared FileSystem Master-slave deployment approach is primarily through the sharing of storage directories for Master and slave, and all ACTIVEMQ applications are constantly gaining control of the shared directory, which application has grabbed control, It becomes master.
Multiple shared storage directory applications, who start first, who can get control of the first shared directory become master, other applications can only be used as slave.
Apache ACTIVEMQ The original configuration content of the single point configuration:
Sharedfile System Master Slave modified to:
Create the Sharebrokerdata folder first in the D:\ActiveMQ cluster directory.
Attention:
1. As mentioned earlier, if you deploy multiple AMQ on a single device, you need to modify the corresponding port number, such as AMQ external listening port 61616 and jetty listening port 8161.
2. If multiple sets of AMQ are deployed on different devices, the directory should point to a remote system directory (Distributed File System)
3. The client is connected by failover mode, multiple AMQ instance addresses are separated by commas, and when an instance disconnects, it is automatically reconnected, but if all instances are invalidated, failover will wait indefinitely by default without prompting.
The following is an example of deploying two amq on a single device:
ActiveMQ A
1.activemq.xml Modify the Listening port:
<transportConnectors>
<!--DOS protection, limit concurrent connections to $ and frame size to 100MB--> ;
<!--add &wireformat.maxinactivityduration=0--
<transportconnector name= "Openwire" uri= "tcp ://0.0.0.0:61616?maximumconnections=1000&wireformat.maxframesize=104857600& Wireformat.maxinactivityduration=0 "discoveryuri=" Multicast://default "/>
<transportconnector name=" AMQP "uri=" amqp://0.0.0.0:5672?maximumconnections=1000&wireformat.maxframesize=104857600& Wireformat.maxinactivityduration=0 "/>
</transportConnectors>
2.jetty.xml Modify the Listening port:
<property name= "Connectors" >
<list>
<bean id= "Connector" class= " Org.eclipse.jetty.server.nio.SelectChannelConnector ">
<property name=" Port "value=" 8166 "/>
< /bean>
<!--
Enable This connector if your wish to use HTTPS with Web console
-
<!--
< Bean id= "Secureconnector" class= "Org.eclipse.jetty.server.ssl.SslSelectChannelConnector" >
<property Name= "Port" value= "8162"/>
<property name= "KeyStore" value= "File:${activemq.conf}/broker.ks"/>
<property name= "password" value= "password"/>
</bean>
</list>
ActiveMQ B
1.activemq.xml Modify the Listening port:
<transportConnectors>
<!--DOS protection, limit concurrent connections to $ and frame size to 100MB--> ;
<!--add &wireformat.maxinactivityduration=0--
<transportconnector name= "Openwire" uri= "tcp ://0.0.0.0:61617?maximumconnections=1000&wireformat.maxframesize=104857600& Wireformat.maxinactivityduration=0 "discoveryuri=" Multicast://default "/>
<transportconnector name=" AMQP "uri=" amqp://0.0.0.0:5673?maximumconnections=1000&wireformat.maxframesize=104857600& Wireformat.maxinactivityduration=0 "/>
2.jetty.xml Modify the Listening port:
<property name= "Connectors" >
<list>
<bean id= "Connector" class= " Org.eclipse.jetty.server.nio.SelectChannelConnector ">
<property name=" Port "value=" 8167 "/>
< /bean>
<!--
Enable This connector if your wish to use HTTPS with Web console
-
<!--
< Bean id= "Secureconnector" class= "Org.eclipse.jetty.server.ssl.SslSelectChannelConnector" >
<property Name= "Port" value= "8162"/>
<property name= "KeyStore" value= "File:${activemq.conf}/broker.ks"/>
<property name= "password" value= "password"/>
</bean>
</list>
Java Test Program code:
1.Producer:
Import javax.jms.Connection;
Import Javax.jms.DeliveryMode;
Import javax.jms.Destination;
Import javax.jms.JMSException;
Import Javax.jms.MessageProducer;
Import javax.jms.Session;
Import Javax.jms.TextMessage;
Import Org.apache.activemq.ActiveMQConnectionFactory; public class Producertool {private String subject = "TOOL.
DEFAULT ";
Private Destination Destination = null;
Private Connection Connection = null;
Private session session = NULL;
Private MessageProducer producer = null; Initialize private void Initialize () throws JMSException, Exception {activemqconnectionfactory CONNECTIONFAC Tory = new Activemqconnectionfactory ("Failover: (tcp://172.16.30.11:61616?wireformat.maxinactivityduration=0,tcp:/
/172.16.30.11:61617?wireformat.maxinactivityduration=0) ");
Connection = Connectionfactory.createconnection ();
Session = Connection.createsession (Boolean.false, Session.auto_acknowledge); Destination = Session.createqueue (subject);
Producer = Session.createproducer (destination);
Producer.setdeliverymode (deliverymode.non_persistent); }//Send message public void Producemessage (String message) throws JMSException, Exception {Initial
Ize ();
TextMessage msg = session.createtextmessage (message);
Connection.start ();
SYSTEM.OUT.PRINTLN ("producer:->sending message:" + message);
Producer.send (msg);
System.out.println ("Producer:->message sent complete!"); }//close connection public void close () throws JMSException {System.out.println ("Producer:->closin
G Connection ");
if (producer! = null) producer.close ();
if (session! = NULL) session.close ();
if (connection! = null) connection.close ();
}
}
Import javax.jms.Connection;
Import javax.jms.Destination;
Import javax.jms.JMSException;
Import Javax.jms.Message;
Import Javax.jms.MessageConsumer;
Import Javax.jms.MessageListener;
Import javax.jms.Session;
Import Javax.jms.TextMessage;
Import Org.apache.activemq.ActiveMQConnectionFactory; public class Consumertool implements MessageListener {private String subject = "TOOL.
DEFAULT ";
Private Destination Destination = null;
Private Connection Connection = null;
Private session session = NULL;
private Messageconsumer consumer = null; Initialize private void Initialize () throws JMSException, Exception {activemqconnectionfactory connectionf
Actory = new Activemqconnectionfactory ("Failover: (tcp://172.16.30.11:61616,tcp://172.16.30.11:61617)");
Connection = Connectionfactory.createconnection ();
Session = Connection.createsession (Boolean.false, Session.auto_acknowledge); Destination = Session.createqueue (subject);
Consumer = session.createconsumer (destination);
}//Consumer message public void Consumemessage () throws JMSException, Exception {initialize ();
Connection.start ();
System.out.println ("Consumer:->begin listening ...");
Consumer.setmessagelistener (this);
Message message = Consumer.receive (); }//close connection public void close () throws JMSException {System.out.println ("consumer:->closing
Connection ");
if (consumer! = null) consumer.close ();
if (session! = NULL) session.close ();
if (connection! = null) connection.close (); }//Message processing function public void onMessage (message message) {try {if (message instance of TextMessage) {TextMessage txtmsg = (textmessage) message;
String msg = Txtmsg.gettext ();
System.out.println ("consumer:->received:" + msg);
} else {System.out.println ("consumer:->received:" + message); }} catch (JMSException e) {//TODO auto-generated catch block e.printstacktr
Ace (); }
}
}
2.Consumer:
Import javax.jms.Connection;
Import javax.jms.Destination;
Import javax.jms.JMSException;
Import Javax.jms.Message;
Import Javax.jms.MessageConsumer;
Import Javax.jms.MessageListener;
Import javax.jms.Session;
Import Javax.jms.TextMessage;
Import Org.apache.activemq.ActiveMQConnectionFactory; public class Consumertool implements MessageListener {private String subject = "TOOL.
DEFAULT ";
Private Destination Destination = null;
Private Connection Connection = null;
Private session session = NULL;
private Messageconsumer consumer = null; Initialize private void Initialize () throws JMSException, Exception {activemqconnectionfactory connectionf
Actory = new Activemqconnectionfactory ("Failover: (tcp://172.16.30.11:61616,tcp://172.16.30.11:61617)");
Connection = Connectionfactory.createconnection ();
Session = Connection.createsession (Boolean.false, Session.auto_acknowledge); Destination = Session.createqueue (subject);
Consumer = session.createconsumer (destination);
}//Consumer message public void Consumemessage () throws JMSException, Exception {initialize ();
Connection.start ();
System.out.println ("Consumer:->begin listening ...");
Consumer.setmessagelistener (this);
Message message = Consumer.receive (); }//close connection public void close () throws JMSException {System.out.println ("consumer:->closing
Connection ");
if (consumer! = null) consumer.close ();
if (session! = NULL) session.close ();
if (connection! = null) connection.close (); }//Message processing function public void onMessage (message message) {try {if (message instance of TextMessage) {TextMessage txtmsg = (textmessage) message;
String msg = Txtmsg.gettext ();
System.out.println ("consumer:->received:" + msg);
} else {System.out.println ("consumer:->received:" + message); }} catch (JMSException e) {//TODO auto-generated catch block e.printstacktr
Ace (); }
}
}
3.Main
Import javax.jms.JMSException;
public class Test {
/**
* @param args
*
/public static void main (string[] args) throws JMSException, Excep tion {
Consumertool consumer = new Consumertool ();
Producertool producer = new Producertool ();
Start monitoring
consumer.consumemessage ();
Delay 500 milliseconds after sending the message
Thread.Sleep (+);
Producer.producemessage ("Hello, world!");
Producer.close ();
Stop accepting messages after 500 milliseconds delay
(thread.sleep);
Consumer.close ();
}
}
ActiveMQ A Start-up interface:
ActiveMQ B Start-up interface:
AMQ a first start, lock the file, when AMQ B boot is, cannot lock the file, but will constantly listen to wait.
Run the Java Test Program log:
10:22:43.745 INFO [] org.apache.activemq.transport.failover.failovertransport-successfully connected to tcp:// 172.16.30.11:61616
consumer:->begin Listening
... 10:22:45.623 INFO [] org.apache.activemq.transport.failover.failovertransport-successfully connected to tcp:// 172.16.30.11:61616?wireformat.maxinactivityduration=0
producer:->sending Message:hello, world!
Producer:->message sent complete!
producer:->closing connection
Consumer:->received:hello, world!
ActiveMQ A Management Interface:
Exception handling:
After configuring the ACTIVEMQ, the first few times have been successfully started. One day when startup found that the boot is unsuccessful, check the error log found the following prompt:
Failed to start Apache ActiveMQ (localhost, ID:-P c--*-0:1). Reason:java.io.IOException:Transport Connector could not being registered in jmx:failed to bind to server socket:tcp://0. 0.0.0:61616?maximumconnections=1000&wireformat.maxframesize=104857600 due to:java.net.BindException:Address Already in Use:jvm_bind.
1. To see if the port is occupied, use the Netstat-ano command to view the port usage, and find that no ports are occupied.
2. Provide network address translation, addressing, name resolution, and/or intrusion protection services on the running Internet Connection Sharing (ICS) for the Home and small office network in the service of the Control Panel he occupies the port.
3. Turn off the service and start actviemq successfully.
2, Broker-cluster Deployment method
The previous Master-slave approach solves the problem of high availability of multi-service hot spares, but does not solve load balancing and distributed issues. The deployment of Broker-cluster can solve the problem of load balancing.
Broker-cluster deployment mode, each broker connects to each other through the network and shares the queue. When a message is received in the pending state of the queue-a specified above broker-a, there is no consumer connection broker-a at this time. If the broker-b in the cluster is consumed by a consumer in the consumption queue-a, then Broker-b will first get the message above BROKER-A through the internal network and notify its own consumer to consume.
1) Static Broker-cluster deployment
statically specifies the other broker in the Activemq.xml file that the broker needs to establish a bridge connection:
1. First add the Networkconnector node to the BROKER-A node:
<networkConnectors>
<networkconnector uri= "static: (tcp://0.0.0.0:61617)" duplex= "false"/>
2. Modify the service provider port in the BROKER-A node to 61616:
<transportConnectors>
<transportconnectorname= "Openwire" uri= "tcp://0.0.0.0:61616? maximumconnections=1000&wireformat.maxframesize=104857600 "/>
3. Add the Networkconnector node to the Broker-b node:
<networkConnectors>
<networkconnector uri= "static: (tcp://0.0.0.0:61616)" duplex= "false"/>
4. Modify the service provider port in the BROKER-A node to 61617:
<transportConnectors>
<transportconnectorname= "Openwire" uri= "tcp://0.0.0.0:61617? maximumconnections=1000&wireformat.maxframesize=104857600 "/>
5. Start Broker-a and Broker-b respectively.
2) Dynamic Broker-cluster deployment
Other brokers that broker needs to establish bridge connections are not directly specified in the Activemq.xml file, and are dynamically looked up by ACTIVEMQ after startup:
1. First add the Networkconnector node to the BROKER-A node:
<networkConnectors>
<networkconnectoruri= "Multicast://default"
dynamiconly= "true"
Networkttl= "3"
prefetchsize= "1"
decreasenetworkconsumerpriority= "true"/>
2. Modify the service provider port in the BROKER-A node to 61616:
<transportConnectors>
<transportconnectorname= "Openwire" uri= "tcp://0.0.0.0:61616? "Discoveryuri=" Multicast://default "/>
3. Add the Networkconnector node to the Broker-b node:
<networkConnectors>
<networkconnectoruri= "Multicast://default"
dynamiconly= "true"
Networkttl= "3"
prefetchsize= "1"